Compare commits

...

54 Commits

Author SHA1 Message Date
fefee11301 Release 2.55.0 (#3034) 2024-02-22 20:26:39 +01:00
40836b745b Feature/improve validation for currency in endpoints (#3030)
* Improve validation for currency

* Update changelog
2024-02-22 20:25:22 +01:00
07eabac059 Feature/add missing database indexes part 2 (#3033)
* Add missing database indexes (for orderBy and where clauses)

* Update changelog
2024-02-22 20:21:50 +01:00
48b412cfb8 Feature/harmonize setting of default locale (#3032)
* Harmonize setting of default locale

* Update changelog
2024-02-22 20:10:27 +01:00
b62488628c Prettify markup (#3029) 2024-02-21 09:58:15 +01:00
982c71c728 Feature/set angular parser in prettierrc (#3028)
* Set parser to angular

* Update changelog
2024-02-20 19:54:03 +01:00
5aa16a3779 Release 2.54.0 (#3027) 2024-02-19 19:47:37 +01:00
93de25e5b6 Feature/add missing database indexes (#3026)
* Add missing database indexes

* Update changelog
2024-02-19 19:45:52 +01:00
9acdb41aa2 Refactor params to object (#2987) 2024-02-19 19:32:10 +01:00
ffbdfb86ec Release 2.53.1 (#3025) 2024-02-18 18:56:34 +01:00
be7f6bb657 Feature/add inactive as user role (#3024)
* Add INACTIVE as user role

* Update changelog
2024-02-18 18:54:49 +01:00
6f7cbc93b9 Add missing type (#3023) 2024-02-18 18:54:36 +01:00
0b5c71130d Update OSS friends (#3008) 2024-02-18 18:50:04 +01:00
0578c645d1 Release 2.53.0 (#3021) 2024-02-18 14:39:10 +01:00
67ae86763e Handle premium data provider in getQuotes() (#3020)
* Handle premium data provider in getQuotes()
2024-02-18 14:37:42 +01:00
266c0a9a2c Feature/eliminate search request in get quotes of eod service (#3019)
* Eliminate search request to get quotes

* Update changelog
2024-02-18 14:14:25 +01:00
a3cdb23776 Feature/refactor query to filter activities of excluded accounts (#3016)
* Refactor query to filter activities of excluded accounts

* Update changelog
2024-02-18 12:29:00 +01:00
e1371a8d2b Clean up (#3018) 2024-02-18 12:27:34 +01:00
448cea0b69 Feature/improve usability of holdings table (#3017)
* Improve usability

* Update changelog
2024-02-18 10:18:53 +01:00
ad42c0bf28 Enable FAQ link for self-hoster (#3015) 2024-02-18 08:53:01 +01:00
f50670c7fe Feature/improve language localization for de 20240217 (#3014)
* Update translations

* Update changelog
2024-02-18 08:51:36 +01:00
c0029d3b1d Feature/upgrade ng extract i18n merge to version 2.10.0 (#3013)
* Upgrade ng-extract-i18n-merge to version 2.10.0

* Update changelog
2024-02-17 22:15:50 +01:00
2518a8fd9d Feature/add accounts tab to position detail dialog (#3012)
* Add accounts tab to position detail dialog

* Update changelog
2024-02-17 21:32:56 +01:00
572dcf075a Release 2.52.0 (#3011) 2024-02-16 20:05:01 +01:00
29cb83d469 Bugfix/improve x axis scale of dividend and investment timeline (#3010)
* Improve X-axis scale

* Update changelog
2024-02-16 20:03:20 +01:00
cac73ac111 Feature/divide faq page in three sections (#3003)
* Divide FAQ page in three sections

* General
* Cloud (SaaS)
* Self-Hosting

* Update changelog
2024-02-16 18:57:34 +01:00
02cf4295a9 Feature/add loading indicator to dividend and investment timelines (#3007)
* Add loading indicators

* Dividend timeline
* Investment timeline

* Update changelog
2024-02-16 09:43:51 +01:00
78b3328bf7 Add activities count (#3005) 2024-02-15 10:25:47 +01:00
e0d6d9e8ca Migrate if / else to control flow (#3001) 2024-02-13 20:46:21 +01:00
54310f2214 Feature/add support for jupiter cryptocurrency (#2999)
* Add JUP29210

* Update changelog
2024-02-13 19:46:15 +01:00
1fec49fbc2 Improve states (#3000) 2024-02-13 19:44:17 +01:00
d00489b547 Release 2.51.0 (#2998) 2024-02-12 20:37:07 +01:00
2985dd67c5 Feature/improve ordered list in safari (#2996)
* Improve ordered list in Safari (without text-truncate)

* Update changelog
2024-02-12 20:35:16 +01:00
5eba764c04 Feature/upgrade eslint dependencies 20240212 (#2995)
* Upgrade eslint dependencies

* Update changelog
2024-02-12 17:22:29 +01:00
cc0ce18627 Bugfix/fix date conversion in import of historical market data (#2994)
* Fix date conversion

* Update changelog
2024-02-12 17:21:22 +01:00
b758654158 Fix renew plan label (#2993) 2024-02-11 21:37:11 +01:00
d5d40c0ea1 Migrate to control flow (#2991)
* Migrate to control flow
2024-02-11 20:51:06 +01:00
fd294d4d2b Migrate to control flow (#2992) 2024-02-11 20:47:24 +01:00
e82cf2e7d0 Feature/upgrade nx to version 18.0.4 (#2990)
* Upgrade Nx to version 18.0.4

* Update changelog
2024-02-11 20:19:45 +01:00
446c7cb517 Remove closing tags of mat-* components (#2989) 2024-02-11 18:12:16 +01:00
e921ed7f52 Reorder imports (#2988) 2024-02-11 17:50:18 +01:00
865402be3a Feature/replace import sort with prettier plugin sort imports (#2872)
* Replace import-sort with prettier-plugin-sort-imports

* Update changelog
2024-02-11 17:26:35 +01:00
6eb659d7e6 Release 2.50.0 (#2984) 2024-02-11 12:41:58 +01:00
37430b7bdc Feature/upgrade prisma to version 5.9.1 (#2983)
* Upgrade prisma to version 5.9.1

* Update changelog
2024-02-11 12:38:49 +01:00
ef9d77312e Introduce renewal-early-bird (#2982) 2024-02-11 12:33:34 +01:00
ccaf06360a Feature/introduce admin setting to disable data gathering (#2981)
* Introduce setting to disable data gathering

* Update changelog
2024-02-11 10:06:07 +01:00
f83e75df44 Feature/harmonize env variables of various api keys (#2980)
* Harmonize env variables of various API keys

* Update changelog
2024-02-11 09:44:12 +01:00
00a2b60eb5 Release 2.49.0 (#2979) 2024-02-09 19:30:00 +01:00
fcbf2f1645 Feature/remove lazy from name of activities table (#2978)
* Remove lazy from name

* Update translations
2024-02-09 18:48:05 +01:00
460266a501 Feature/upgrade yahoo finance2 to version 2.9.1 (#2963)
* Upgrade yahoo-finance2 to version 2.9.1

* Update changelog
2024-02-09 18:41:18 +01:00
9fe90273c7 Feature/move assistant to general availability (#2977)
* Move assistant from experimental to general availability

* Update changelog
2024-02-09 18:25:15 +01:00
4078229fe6 Feature/add button to apply filters in assistant (#2971)
* Add apply filters button

* Update changelog
2024-02-09 09:45:54 +01:00
609c03f174 Add analytics image (#2970) 2024-02-08 08:00:04 +01:00
e7d4641d13 Feature/reload data on logo click (#2959)
* Reload data on logo click

* Update changelog
2024-02-07 21:03:28 +01:00
471 changed files with 13866 additions and 13644 deletions

View File

@ -1,3 +1,4 @@
/.nx/cache
/apps/client/src/polyfills.ts
/dist
/test/import

View File

@ -9,7 +9,26 @@
],
"attributeSort": "ASC",
"endOfLine": "auto",
"plugins": ["prettier-plugin-organize-attributes"],
"importOrder": ["^@ghostfolio/(.*)$", "<THIRD_PARTY_MODULES>", "^[./]"],
"importOrderSeparation": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
},
{
"files": "*.ts",
"options": {
"importOrderParserPlugins": ["decorators-legacy", "typescript"]
}
}
],
"plugins": [
"prettier-plugin-organize-attributes",
"@trivago/prettier-plugin-sort-imports"
],
"printWidth": 80,
"singleQuote": true,
"tabWidth": 2,

View File

@ -5,6 +5,113 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 2.55.0 - 2024-02-22
### Added
- Added indexes for `alias`, `granteeUserId` and `userId` to the access database table
- Added indexes for `currency`, `name` and `userId` to the account database table
- Added an index for `accountId`, `date` and `updatedAt` to the account balance database table
- Added an index for `userId` to the auth device database table
- Added an index for `marketPrice` and `state` to the market data database table
- Added indexes for `date`, `isDraft` and `userId` to the order database table
- Added an index for `name` to the platform database table
- Added indexes for `assetClass`, `currency`, `dataSource`, `isin`, `name` and `symbol` to the symbol profile database table
- Added an index for `userId` to the subscription database table
- Added an index for `name` to the tag database table
- Added indexes for `accessToken`, `createdAt`, `provider`, `role` and `thirdPartyId` to the user database table
### Changed
- Improved the validation for `currency` in various endpoints
- Harmonized the setting of a default locale in various components
- Set the parser to `angular` in the `prettier` options
## 2.54.0 - 2024-02-19
### Added
- Added an index for `id` to the account database table
- Added indexes for `dataSource` and `date` to the market data database table
- Added an index for `accountId` to the order database table
## 2.53.1 - 2024-02-18
### Added
- Added an accounts tab to the position detail dialog
- Added `INACTIVE` as a new user role
### Changed
- Improved the usability of the holdings table
- Refactored the query to filter activities of excluded accounts
- Eliminated the search request to get quotes in the _EOD Historical Data_ service
- Improved the language localization for German (`de`)
- Upgraded `ng-extract-i18n-merge` from version `2.9.1` to `2.10.0`
## 2.52.0 - 2024-02-16
### Added
- Added a loading indicator to the dividend timeline on the analysis page
- Added a loading indicator to the investment timeline on the analysis page
- Added support for the cryptocurrency _Jupiter_ (`JUP29210-USD`)
### Changed
- Divided the content of the Frequently Asked Questions (FAQ) page into three sections: _General_, _Cloud (SaaS)_ and _Self-Hosting_
### Fixed
- Fixed an issue with the X-axis scale of the dividend timeline on the analysis page
- Fixed an issue with the X-axis scale of the investment timeline on the analysis page
## 2.51.0 - 2024-02-12
### Changed
- Improved the ordered list of the _Top 3_ and _Bottom 3_ performers on the analysis page in Safari
- Replaced `import-sort` with `prettier-plugin-sort-imports`
- Upgraded `eslint` dependencies
- Upgraded `Nx` from version `17.2.8` to `18.0.4`
### Fixed
- Fixed the date conversion of the import of historical market data in the admin control panel
## 2.50.0 - 2024-02-11
### Added
- Introduced a setting to disable the data gathering in the admin control
### Changed
- Harmonized the environment variables of various API keys
- Upgraded `prisma` from version `5.8.1` to `5.9.1`
### Todo
- Rename the environment variable from `ALPHA_VANTAGE_API_KEY` to `API_KEY_ALPHA_VANTAGE`
- Rename the environment variable from `BETTER_UPTIME_API_KEY` to `API_KEY_BETTER_UPTIME`
- Rename the environment variable from `EOD_HISTORICAL_DATA_API_KEY` to `API_KEY_EOD_HISTORICAL_DATA`
- Rename the environment variable from `FINANCIAL_MODELING_PREP_API_KEY` to `API_KEY_FINANCIAL_MODELING_PREP`
- Rename the environment variable from `OPEN_FIGI_API_KEY` to `API_KEY_OPEN_FIGI`
- Rename the environment variable from `RAPID_API_API_KEY` to `API_KEY_RAPID_API`
## 2.49.0 - 2024-02-09
### Added
- Added a button to apply the active filters in the assistant
### Changed
- Moved the assistant from experimental to general availability
- Improved the usability by reloading the content with a logo click on the home page
- Upgraded `yahoo-finance2` from version `2.9.0` to `2.9.1`
## 2.48.1 - 2024-02-06
### Fixed

View File

@ -280,6 +280,10 @@ Not sure what to work on? We have got some ideas. Please join the Ghostfolio [Sl
If you like to support this project, get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio).
## Analytics
![Alt](https://repobeats.axiom.co/api/embed/281a80b2d0c4af1162866c24c803f1f18e5ed60e.svg 'Repobeats analytics image')
## License
© 2021 - 2024 [Ghostfolio](https://ghostfol.io)

View File

@ -4,6 +4,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { Access } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
Controller,

View File

@ -1,5 +1,6 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { AccessController } from './access.controller';

View File

@ -1,5 +1,6 @@
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { AccessWithGranteeUser } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
import { Access, Prisma } from '@prisma/client';

View File

@ -2,6 +2,7 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Controller,
Delete,

View File

@ -1,5 +1,6 @@
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { AccountBalanceController } from './account-balance.controller';

View File

@ -2,6 +2,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { AccountBalancesResponse, Filter } from '@ghostfolio/common/interfaces';
import { UserWithSettings } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
import { AccountBalance, Prisma } from '@prisma/client';

View File

@ -14,6 +14,7 @@ import type {
AccountWithValue,
RequestWithUser
} from '@ghostfolio/common/types';
import {
Body,
Controller,

View File

@ -7,6 +7,7 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { AccountController } from './account.controller';

View File

@ -2,6 +2,7 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/accou
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { Filter } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common';
import { Account, Order, Platform, Prisma } from '@prisma/client';
import Big from 'big.js';
@ -20,10 +21,8 @@ export class AccountService {
public async account({
id_userId
}: Prisma.AccountWhereUniqueInput): Promise<Account | null> {
const { id, userId } = id_userId;
const [account] = await this.accounts({
where: { id, userId }
where: id_userId
});
return account;

View File

@ -1,6 +1,7 @@
import { Transform, TransformFnParams } from 'class-transformer';
import {
IsBoolean,
IsISO4217CurrencyCode,
IsNumber,
IsOptional,
IsString,
@ -19,7 +20,7 @@ export class CreateAccountDto {
)
comment?: string;
@IsString()
@IsISO4217CurrencyCode()
currency: string;
@IsOptional()

View File

@ -1,6 +1,7 @@
import { Transform, TransformFnParams } from 'class-transformer';
import {
IsBoolean,
IsISO4217CurrencyCode,
IsNumber,
IsOptional,
IsString,
@ -19,7 +20,7 @@ export class UpdateAccountDto {
)
comment?: string;
@IsString()
@IsISO4217CurrencyCode()
currency: string;
@IsString()

View File

@ -25,6 +25,7 @@ import type {
MarketDataPreset,
RequestWithUser
} from '@ghostfolio/common/types';
import {
Body,
Controller,
@ -255,7 +256,7 @@ export class AdminController {
dataSource,
marketPrice,
symbol,
date: resetHours(parseISO(date)),
date: parseISO(date),
state: 'CLOSE'
})
);

View File

@ -8,6 +8,7 @@ import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-da
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { AdminController } from './admin.controller';

View File

@ -22,6 +22,7 @@ import {
UniqueAsset
} from '@ghostfolio/common/interfaces';
import { MarketDataPreset } from '@ghostfolio/common/types';
import { BadRequestException, Injectable } from '@nestjs/common';
import {
AssetSubClass,
@ -225,7 +226,7 @@ export class AdminService {
this.prismaService.symbolProfile.count({ where })
]);
let marketData = assetProfiles.map(
let marketData: AdminMarketDataItem[] = assetProfiles.map(
({
_count,
assetClass,
@ -455,7 +456,10 @@ export class AdminService {
const subscription = this.configurationService.get(
'ENABLE_FEATURE_SUBSCRIPTION'
)
? this.subscriptionService.getSubscription(Subscription)
? this.subscriptionService.getSubscription({
createdAt,
subscriptions: Subscription
})
: undefined;
return {

View File

@ -2,6 +2,7 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { AdminJobs } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import {
Controller,
Delete,

View File

@ -1,4 +1,5 @@
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module';
import { Module } from '@nestjs/common';
import { QueueController } from './queue.controller';

View File

@ -3,6 +3,7 @@ import {
QUEUE_JOB_STATUS_LIST
} from '@ghostfolio/common/config';
import { AdminJobs } from '@ghostfolio/common/interfaces';
import { InjectQueue } from '@nestjs/bull';
import { Injectable } from '@nestjs/common';
import { JobStatus, Queue } from 'bull';

View File

@ -2,6 +2,7 @@ import { AssetClass, AssetSubClass, Prisma } from '@prisma/client';
import {
IsArray,
IsEnum,
IsISO4217CurrencyCode,
IsObject,
IsOptional,
IsString
@ -24,7 +25,7 @@ export class UpdateAssetProfileDto {
@IsOptional()
countries?: Prisma.InputJsonArray;
@IsString()
@IsISO4217CurrencyCode()
@IsOptional()
currency?: string;

View File

@ -1,4 +1,5 @@
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { Controller } from '@nestjs/common';
@Controller()

View File

@ -1,22 +1,23 @@
import { join } from 'path';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { CronService } from '@ghostfolio/api/services/cron.service';
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { TwitterBotModule } from '@ghostfolio/api/services/twitter-bot/twitter-bot.module';
import {
DEFAULT_LANGUAGE_CODE,
SUPPORTED_LANGUAGE_CODES
} from '@ghostfolio/common/config';
import { BullModule } from '@nestjs/bull';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ScheduleModule } from '@nestjs/schedule';
import { ServeStaticModule } from '@nestjs/serve-static';
import { StatusCodes } from 'http-status-codes';
import { join } from 'path';
import { AccessModule } from './access/access.module';
import { AccountModule } from './account/account.module';
@ -73,6 +74,7 @@ import { UserModule } from './user/user.module';
PlatformModule,
PortfolioModule,
PrismaModule,
PropertyModule,
RedisCacheModule,
ScheduleModule.forRoot(),
ServeStaticModule.forRoot({

View File

@ -2,6 +2,7 @@ import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.s
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { permissions } from '@ghostfolio/common/permissions';
import { Controller, Delete, Param, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

View File

@ -2,6 +2,7 @@ import { AuthDeviceController } from '@ghostfolio/api/app/auth-device/auth-devic
import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.service';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';

View File

@ -1,5 +1,6 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { Injectable } from '@nestjs/common';
import { AuthDevice, Prisma } from '@prisma/client';

View File

@ -3,6 +3,7 @@ import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
import { OAuthResponse } from '@ghostfolio/common/interfaces';
import {
Body,
Controller,

View File

@ -5,6 +5,7 @@ import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';

View File

@ -1,6 +1,7 @@
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Provider } from '@prisma/client';

View File

@ -1,4 +1,5 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { Injectable, Logger } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Provider } from '@prisma/client';

View File

@ -1,4 +1,5 @@
import { AuthDeviceDto } from '@ghostfolio/api/app/auth-device/auth-device.dto';
import { Provider } from '@prisma/client';
export interface AuthDeviceDialogParams {

View File

@ -2,6 +2,7 @@ import { UserService } from '@ghostfolio/api/app/user/user.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { HEADER_KEY_TIMEZONE } from '@ghostfolio/common/config';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import * as countriesAndTimezones from 'countries-and-timezones';

View File

@ -3,6 +3,7 @@ import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.s
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Inject,
Injectable,

View File

@ -9,6 +9,7 @@ import type {
} from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
Controller,

View File

@ -7,6 +7,7 @@ import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-da
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { BenchmarkController } from './benchmark.controller';

View File

@ -23,6 +23,7 @@ import {
UniqueAsset
} from '@ghostfolio/common/interfaces';
import { BenchmarkTrend } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
import { SymbolProfile } from '@prisma/client';
import Big from 'big.js';

View File

@ -2,6 +2,7 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { permissions } from '@ghostfolio/common/permissions';
import { Controller, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

View File

@ -5,6 +5,7 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { CacheController } from './cache.controller';

View File

@ -1,5 +1,6 @@
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces';
import {
Controller,
Get,

View File

@ -1,4 +1,5 @@
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { Module } from '@nestjs/common';
import { ExchangeRateController } from './exchange-rate.controller';

View File

@ -1,4 +1,5 @@
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { Injectable } from '@nestjs/common';
@Injectable()

View File

@ -2,6 +2,7 @@ import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'
import { ApiService } from '@ghostfolio/api/services/api/api.service';
import { Export } from '@ghostfolio/common/interfaces';
import type { RequestWithUser } from '@ghostfolio/common/types';
import { Controller, Get, Inject, Query, UseGuards } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';

View File

@ -5,6 +5,7 @@ import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { Module } from '@nestjs/common';
import { ExportController } from './export.controller';

View File

@ -2,6 +2,7 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { OrderService } from '@ghostfolio/api/app/order/order.service';
import { environment } from '@ghostfolio/api/environments/environment';
import { Filter, Export } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common';
@Injectable()

View File

@ -1,4 +1,5 @@
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor';
import {
Controller,
Get,

View File

@ -1,6 +1,7 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataEnhancerModule } from '@ghostfolio/api/services/data-provider/data-enhancer/data-enhancer.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { Module } from '@nestjs/common';
import { HealthController } from './health.controller';

View File

@ -1,5 +1,6 @@
import { DataEnhancerService } from '@ghostfolio/api/services/data-provider/data-enhancer/data-enhancer.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { Injectable } from '@nestjs/common';
import { DataSource } from '@prisma/client';

View File

@ -1,5 +1,6 @@
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto';
import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
import { Type } from 'class-transformer';
import { IsArray, IsOptional, ValidateNested } from 'class-validator';

View File

@ -6,6 +6,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { ImportResponse } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
Controller,

View File

@ -10,6 +10,7 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { ImportController } from './import.controller';

View File

@ -24,6 +24,7 @@ import {
OrderWithAccount,
UserWithSettings
} from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
import { DataSource, Prisma, SymbolProfile } from '@prisma/client';
import Big from 'big.js';

View File

@ -1,5 +1,6 @@
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor';
import { InfoItem } from '@ghostfolio/common/interfaces';
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { InfoService } from './info.service';

View File

@ -10,6 +10,7 @@ import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { TagModule } from '@ghostfolio/api/services/tag/tag.module';
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';

View File

@ -28,6 +28,7 @@ import {
} from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import { SubscriptionOffer } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as cheerio from 'cheerio';
@ -59,10 +60,6 @@ export class InfoService {
const globalPermissions: string[] = [];
if (this.configurationService.get('ENABLE_FEATURE_BLOG')) {
globalPermissions.push(permissions.enableBlog);
}
if (this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) {
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
info.fearAndGreedDataSource = encodeDataSource(
@ -351,7 +348,7 @@ export class InfoService {
{
headers: {
Authorization: `Bearer ${this.configurationService.get(
'BETTER_UPTIME_API_KEY'
'API_KEY_BETTER_UPTIME'
)}`
},
// @ts-ignore

View File

@ -1,4 +1,5 @@
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor';
import {
Controller,
Get,

View File

@ -1,5 +1,6 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { LogoController } from './logo.controller';

View File

@ -1,6 +1,7 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { HttpException, Injectable } from '@nestjs/common';
import { DataSource } from '@prisma/client';
import got from 'got';

View File

@ -10,6 +10,7 @@ import {
IsArray,
IsBoolean,
IsEnum,
IsISO4217CurrencyCode,
IsISO8601,
IsNumber,
IsOptional,
@ -38,7 +39,7 @@ export class CreateOrderDto {
)
comment?: string;
@IsString()
@IsISO4217CurrencyCode()
currency: string;
@IsOptional()

View File

@ -9,6 +9,7 @@ import { ImpersonationService } from '@ghostfolio/api/services/impersonation/imp
import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
Controller,

View File

@ -11,6 +11,7 @@ import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-d
import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { OrderController } from './order.controller';

View File

@ -10,6 +10,7 @@ import {
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import { Filter } from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
import {
AssetClass,
@ -300,6 +301,12 @@ export class OrderService {
});
}
if (withExcludedAccounts === false) {
where.Account = {
NOT: { isExcluded: true }
};
}
const [orders, count] = await Promise.all([
this.orders({
orderBy,
@ -321,32 +328,24 @@ export class OrderService {
this.prismaService.order.count({ where })
]);
const activities = orders
.filter((order) => {
return (
withExcludedAccounts ||
!order.Account ||
order.Account?.isExcluded === false
);
})
.map((order) => {
const value = new Big(order.quantity).mul(order.unitPrice).toNumber();
const activities = orders.map((order) => {
const value = new Big(order.quantity).mul(order.unitPrice).toNumber();
return {
...order,
return {
...order,
value,
feeInBaseCurrency: this.exchangeRateDataService.toCurrency(
order.fee,
order.SymbolProfile.currency,
userCurrency
),
valueInBaseCurrency: this.exchangeRateDataService.toCurrency(
value,
feeInBaseCurrency: this.exchangeRateDataService.toCurrency(
order.fee,
order.SymbolProfile.currency,
userCurrency
),
valueInBaseCurrency: this.exchangeRateDataService.toCurrency(
value,
order.SymbolProfile.currency,
userCurrency
)
};
});
order.SymbolProfile.currency,
userCurrency
)
};
});
return { activities, count };
}

View File

@ -9,6 +9,7 @@ import { Transform, TransformFnParams } from 'class-transformer';
import {
IsArray,
IsEnum,
IsISO4217CurrencyCode,
IsISO8601,
IsNumber,
IsOptional,
@ -37,7 +38,7 @@ export class UpdateOrderDto {
)
comment?: string;
@IsString()
@IsISO4217CurrencyCode()
currency: string;
@IsString()

View File

@ -1,6 +1,7 @@
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { permissions } from '@ghostfolio/common/permissions';
import {
Body,
Controller,

View File

@ -1,4 +1,5 @@
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { PlatformController } from './platform.controller';

View File

@ -1,4 +1,5 @@
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { Injectable } from '@nestjs/common';
import { Platform, Prisma } from '@prisma/client';

View File

@ -1,4 +1,5 @@
import { parseDate, resetHours } from '@ghostfolio/common/helper';
import { addDays, endOfDay, isBefore, isSameDay } from 'date-fns';
import { GetValueObject } from './interfaces/get-value-object.interface';

View File

@ -2,6 +2,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { DataSource, MarketData } from '@prisma/client';
import { CurrentRateService } from './current-rate.service';
@ -106,7 +107,8 @@ describe('CurrentRateService', () => {
currentRateService = new CurrentRateService(
dataProviderService,
marketDataService
marketDataService,
null
);
});

View File

@ -6,7 +6,10 @@ import {
ResponseError,
UniqueAsset
} from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common';
import type { RequestWithUser } from '@ghostfolio/common/types';
import { Inject, Injectable } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { isBefore, isToday } from 'date-fns';
import { flatten, isEmpty, uniqBy } from 'lodash';
@ -18,9 +21,11 @@ import { GetValuesParams } from './interfaces/get-values-params.interface';
export class CurrentRateService {
public constructor(
private readonly dataProviderService: DataProviderService,
private readonly marketDataService: MarketDataService
private readonly marketDataService: MarketDataService,
@Inject(REQUEST) private readonly request: RequestWithUser
) {}
// TODO: Pass user instead of using this.request.user
public async getValues({
dataGatheringItems,
dateQuery
@ -39,7 +44,7 @@ export class CurrentRateService {
if (includeToday) {
promises.push(
this.dataProviderService
.getQuotes({ items: dataGatheringItems })
.getQuotes({ items: dataGatheringItems, user: this.request?.user })
.then((dataResultProvider) => {
const result: GetValueObject[] = [];

View File

@ -1,4 +1,5 @@
import { ResponseError, TimelinePosition } from '@ghostfolio/common/interfaces';
import Big from 'big.js';
export interface CurrentPositions extends ResponseError {

View File

@ -4,9 +4,11 @@ import {
HistoricalDataItem
} from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types';
import { Tag } from '@prisma/client';
import { Account, Tag } from '@prisma/client';
export interface PortfolioPositionDetail {
accounts: Account[];
averagePrice: number;
dataProviderInfo: DataProviderInfo;
dividendInBaseCurrency: number;

View File

@ -1,6 +1,7 @@
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
@ -20,7 +21,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -1,6 +1,7 @@
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
@ -20,7 +21,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -2,6 +2,7 @@ import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.s
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service.mock';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
@ -33,7 +34,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -2,6 +2,7 @@ import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.s
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service.mock';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
@ -33,7 +34,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -1,6 +1,7 @@
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
@ -20,7 +21,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -1,6 +1,7 @@
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
@ -20,7 +21,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -1,6 +1,7 @@
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
@ -20,7 +21,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -1,4 +1,5 @@
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import Big from 'big.js';
import { CurrentRateService } from './current-rate.service';
@ -9,7 +10,7 @@ describe('PortfolioCalculator', () => {
let exchangeRateDataService: ExchangeRateDataService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null);
currentRateService = new CurrentRateService(null, null, null);
exchangeRateDataService = new ExchangeRateDataService(
null,

View File

@ -10,6 +10,7 @@ import {
TimelinePosition
} from '@ghostfolio/common/interfaces';
import { GroupBy } from '@ghostfolio/common/types';
import { Logger } from '@nestjs/common';
import { Type as TypeOfOrder } from '@prisma/client';
import Big from 'big.js';

View File

@ -28,6 +28,7 @@ import type {
GroupBy,
RequestWithUser
} from '@ghostfolio/common/types';
import {
Controller,
Get,

View File

@ -12,6 +12,7 @@ import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impe
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { CurrentRateService } from './current-rate.service';

View File

@ -48,6 +48,7 @@ import type {
RequestWithUser,
UserWithSettings
} from '@ghostfolio/common/types';
import { Inject, Injectable } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import {
@ -419,7 +420,7 @@ export class PortfolioService {
);
const [dataProviderResponses, symbolProfiles] = await Promise.all([
this.dataProviderService.getQuotes({ items: dataGatheringItems }),
this.dataProviderService.getQuotes({ user, items: dataGatheringItems }),
this.symbolProfileService.getSymbolProfiles(dataGatheringItems)
]);
@ -656,6 +657,7 @@ export class PortfolioService {
if (orders.length <= 0) {
return {
tags,
accounts: [],
averagePrice: undefined,
dataProviderInfo: undefined,
dividendInBaseCurrency: undefined,
@ -738,6 +740,13 @@ export class PortfolioService {
transactionCount
} = position;
const accounts: PortfolioPositionDetail['accounts'] = uniqBy(
orders,
'Account.id'
).map(({ Account }) => {
return Account;
});
const dividendInBaseCurrency = getSum(
orders
.filter(({ type }) => {
@ -811,6 +820,7 @@ export class PortfolioService {
}
return {
accounts,
firstBuyDate,
marketPrice,
maxPrice,
@ -851,6 +861,7 @@ export class PortfolioService {
};
} else {
const currentData = await this.dataProviderService.getQuotes({
user,
items: [{ dataSource: DataSource.YAHOO, symbol: aSymbol }]
});
const marketPrice = currentData[aSymbol]?.marketPrice;
@ -893,6 +904,7 @@ export class PortfolioService {
orders,
SymbolProfile,
tags,
accounts: [],
averagePrice: 0,
dataProviderInfo: undefined,
dividendInBaseCurrency: 0,
@ -928,6 +940,7 @@ export class PortfolioService {
return type === 'SEARCH_QUERY';
})?.id;
const userId = await this.getUserId(impersonationId, this.request.user.id);
const user = await this.userService.user({ id: userId });
const { portfolioOrders, transactionPoints } =
await this.getTransactionPoints({
@ -968,7 +981,7 @@ export class PortfolioService {
});
const [dataProviderResponses, symbolProfiles] = await Promise.all([
this.dataProviderService.getQuotes({ items: dataGatheringItems }),
this.dataProviderService.getQuotes({ user, items: dataGatheringItems }),
this.symbolProfileService.getSymbolProfiles(
positions.map(({ dataSource, symbol }) => {
return { dataSource, symbol };

View File

@ -1,6 +1,7 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { Rule } from '@ghostfolio/api/models/rule';
import { UserSettings } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common';
@Injectable()

View File

@ -1,5 +1,6 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { CacheModule } from '@nestjs/cache-manager';
import { Module } from '@nestjs/common';
import * as redisStore from 'cache-manager-redis-store';

View File

@ -1,6 +1,7 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable, Logger } from '@nestjs/common';

View File

@ -1,14 +1,14 @@
import * as fs from 'fs';
import * as path from 'path';
import {
DATE_FORMAT,
getYesterday,
interpolate
} from '@ghostfolio/common/helper';
import { Controller, Get, Res, VERSION_NEUTRAL, Version } from '@nestjs/common';
import { format } from 'date-fns';
import { Response } from 'express';
import * as fs from 'fs';
import * as path from 'path';
@Controller('sitemap.xml')
export class SitemapController {

View File

@ -5,6 +5,7 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { SitemapController } from './sitemap.controller';

View File

@ -7,6 +7,7 @@ import {
} from '@ghostfolio/common/config';
import { Coupon } from '@ghostfolio/common/interfaces';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
Controller,

View File

@ -1,6 +1,7 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { Module } from '@nestjs/common';
import { SubscriptionController } from './subscription.controller';

View File

@ -1,8 +1,10 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
import { UserWithSettings } from '@ghostfolio/common/types';
import { parseDate } from '@ghostfolio/common/helper';
import { SubscriptionOffer, UserWithSettings } from '@ghostfolio/common/types';
import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type';
import { Injectable, Logger } from '@nestjs/common';
import { Subscription } from '@prisma/client';
import { addMilliseconds, isBefore } from 'date-fns';
@ -107,17 +109,27 @@ export class SubscriptionService {
}
}
public getSubscription(
aSubscriptions: Subscription[]
): UserWithSettings['subscription'] {
if (aSubscriptions.length > 0) {
const { expiresAt, price } = aSubscriptions.reduce((a, b) => {
public getSubscription({
createdAt,
subscriptions
}: {
createdAt: UserWithSettings['createdAt'];
subscriptions: Subscription[];
}): UserWithSettings['subscription'] {
if (subscriptions.length > 0) {
const { expiresAt, price } = subscriptions.reduce((a, b) => {
return new Date(a.expiresAt) > new Date(b.expiresAt) ? a : b;
});
let offer: SubscriptionOffer = price ? 'renewal' : 'default';
if (isBefore(createdAt, parseDate('2023-01-01'))) {
offer = 'renewal-early-bird';
}
return {
expiresAt,
offer: price ? 'renewal' : 'default',
offer,
type: isBefore(new Date(), expiresAt)
? SubscriptionType.Premium
: SubscriptionType.Basic

View File

@ -1,4 +1,5 @@
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
export interface LookupItem {

View File

@ -3,6 +3,7 @@ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interce
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor';
import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Controller,
Get,

View File

@ -2,6 +2,7 @@ import { ConfigurationModule } from '@ghostfolio/api/services/configuration/conf
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { SymbolController } from './symbol.controller';

View File

@ -7,6 +7,7 @@ import { MarketDataService } from '@ghostfolio/api/services/market-data/market-d
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { HistoricalDataItem } from '@ghostfolio/common/interfaces';
import { UserWithSettings } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
import { format, subDays } from 'date-fns';

View File

@ -1,6 +1,7 @@
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { permissions } from '@ghostfolio/common/permissions';
import {
Body,
Controller,

View File

@ -1,4 +1,5 @@
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { TagController } from './tag.controller';

View File

@ -1,4 +1,5 @@
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { Injectable } from '@nestjs/common';
import { Prisma, Tag } from '@prisma/client';

View File

@ -3,9 +3,11 @@ import type {
DateRange,
ViewMode
} from '@ghostfolio/common/types';
import {
IsArray,
IsBoolean,
IsISO4217CurrencyCode,
IsISO8601,
IsIn,
IsNumber,
@ -18,8 +20,8 @@ export class UpdateUserSettingDto {
@IsOptional()
annualInterestRate?: number;
@IsISO4217CurrencyCode()
@IsOptional()
@IsString()
baseCurrency?: string;
@IsString()

View File

@ -2,8 +2,13 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { User, UserSettings } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import {
hasPermission,
hasRole,
permissions
} from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
Controller,
@ -58,6 +63,13 @@ export class UserController {
public async getUser(
@Headers('accept-language') acceptLanguage: string
): Promise<User> {
if (hasRole(this.request.user, 'INACTIVE')) {
throw new HttpException(
getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS),
StatusCodes.TOO_MANY_REQUESTS
);
}
return this.userService.getUser(
this.request.user,
acceptLanguage?.split(',')?.[0]

Some files were not shown because too many files have changed in this diff Show More