Browse Source

Task/deprecate platform endpoints in favor of platforms endpoints (#8255)

* Deprecate platform endpoints in favor of platforms endpoints

* Update changelog
pull/8257/head
Thomas Kaul 3 days ago
committed by GitHub
parent
commit
cea7c303c6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 28
      apps/api/src/app/__snapshots__/app.module.spec.ts.snap
  3. 2
      apps/api/src/app/app.module.ts
  4. 4
      apps/api/src/app/endpoints/platforms/platform.controller.ts
  5. 113
      apps/api/src/app/endpoints/platforms/platforms.controller.ts
  6. 5
      apps/api/src/app/endpoints/platforms/platforms.module.ts
  7. 2
      apps/api/src/app/import/import.module.ts
  8. 2
      apps/api/src/app/import/import.service.ts
  9. 2
      apps/api/src/app/info/info.module.ts
  10. 2
      apps/api/src/services/platform/platform.module.ts
  11. 7
      apps/api/src/services/platform/platform.service.ts
  12. 20
      apps/client/src/app/components/admin-platform/admin-platform.component.ts
  13. 2
      libs/common/src/lib/interfaces/index.ts
  14. 6
      libs/common/src/lib/interfaces/responses/platform-response.interface.ts
  15. 4
      libs/common/src/lib/interfaces/responses/platforms-response.interface.ts
  16. 29
      libs/ui/src/lib/services/admin.service.ts
  17. 18
      libs/ui/src/lib/services/data.service.ts

1
CHANGELOG.md

@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Extracted the file drop area of the import activities dialog to a reusable component - Extracted the file drop area of the import activities dialog to a reusable component
- Improved the performance of the historical market data table of the admin control panel by loading only the latest market price per asset profile - Improved the performance of the historical market data table of the admin control panel by loading only the latest market price per asset profile
- Introduced a cooldown of 12 hours for the asset profile and exchange rate gathering on activity creation by retaining the completed jobs - Introduced a cooldown of 12 hours for the asset profile and exchange rate gathering on activity creation by retaining the completed jobs
- Deprecated the `api/v1/platform` endpoints in favor of the `api/v1/platforms` endpoints
### Fixed ### Fixed

28
apps/api/src/app/__snapshots__/app.module.spec.ts.snap

@ -134,6 +134,15 @@ exports[`AppModule should keep the security of each route 1`] = `
"interceptors": [], "interceptors": [],
"permission": "deletePlatform", "permission": "deletePlatform",
}, },
"DELETE /platforms/:id": {
"allowDuringImpersonation": true,
"guards": [
"AuthGuard('jwt')",
"HasPermissionGuard",
],
"interceptors": [],
"permission": "deletePlatform",
},
"DELETE /tags/:id": { "DELETE /tags/:id": {
"allowDuringImpersonation": true, "allowDuringImpersonation": true,
"guards": [ "guards": [
@ -557,6 +566,7 @@ exports[`AppModule should keep the security of each route 1`] = `
"permission": "readPlatformsWithAccountCount", "permission": "readPlatformsWithAccountCount",
}, },
"GET /platforms": { "GET /platforms": {
"allowDuringImpersonation": true,
"guards": [ "guards": [
"AuthGuard('jwt')", "AuthGuard('jwt')",
"HasPermissionGuard", "HasPermissionGuard",
@ -1021,6 +1031,15 @@ exports[`AppModule should keep the security of each route 1`] = `
"interceptors": [], "interceptors": [],
"permission": "createPlatform", "permission": "createPlatform",
}, },
"POST /platforms": {
"allowDuringImpersonation": true,
"guards": [
"AuthGuard('jwt')",
"HasPermissionGuard",
],
"interceptors": [],
"permission": "createPlatform",
},
"POST /subscription/redeem-coupon": { "POST /subscription/redeem-coupon": {
"allowDuringImpersonation": true, "allowDuringImpersonation": true,
"guards": [ "guards": [
@ -1144,6 +1163,15 @@ exports[`AppModule should keep the security of each route 1`] = `
"interceptors": [], "interceptors": [],
"permission": "updatePlatform", "permission": "updatePlatform",
}, },
"PUT /platforms/:id": {
"allowDuringImpersonation": true,
"guards": [
"AuthGuard('jwt')",
"HasPermissionGuard",
],
"interceptors": [],
"permission": "updatePlatform",
},
"PUT /portfolio/holding/:dataSource/:symbol/tags": { "PUT /portfolio/holding/:dataSource/:symbol/tags": {
"guards": [ "guards": [
"AuthGuard('jwt')", "AuthGuard('jwt')",

2
apps/api/src/app/app.module.ts

@ -63,7 +63,6 @@ import { HealthModule } from './health/health.module';
import { ImportModule } from './import/import.module'; import { ImportModule } from './import/import.module';
import { InfoModule } from './info/info.module'; import { InfoModule } from './info/info.module';
import { LogoModule } from './logo/logo.module'; import { LogoModule } from './logo/logo.module';
import { PlatformModule } from './platform/platform.module';
import { PortfolioModule } from './portfolio/portfolio.module'; import { PortfolioModule } from './portfolio/portfolio.module';
import { SubscriptionModule } from './subscription/subscription.module'; import { SubscriptionModule } from './subscription/subscription.module';
import { SymbolModule } from './symbol/symbol.module'; import { SymbolModule } from './symbol/symbol.module';
@ -130,7 +129,6 @@ import { UserModule } from './user/user.module';
LogoModule, LogoModule,
MarketDataModule, MarketDataModule,
McpModule, McpModule,
PlatformModule,
PlatformsModule, PlatformsModule,
PortfolioModule, PortfolioModule,
PortfolioSnapshotQueueModule, PortfolioSnapshotQueueModule,

4
apps/api/src/app/platform/platform.controller.ts → apps/api/src/app/endpoints/platforms/platform.controller.ts

@ -1,6 +1,7 @@
import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-during-impersonation.decorator'; import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-during-impersonation.decorator';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { PlatformService } from '@ghostfolio/api/services/platform/platform.service';
import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos'; import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos';
import { permissions } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions';
@ -19,8 +20,7 @@ import { AuthGuard } from '@nestjs/passport';
import { Platform } from '@prisma/client'; import { Platform } from '@prisma/client';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { PlatformService } from './platform.service'; /** @deprecated */
@AllowDuringImpersonation() @AllowDuringImpersonation()
@Controller('platform') @Controller('platform')
export class PlatformController { export class PlatformController {

113
apps/api/src/app/endpoints/platforms/platforms.controller.ts

@ -1,24 +1,125 @@
import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-during-impersonation.decorator';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { PlatformsResponse } from '@ghostfolio/common/interfaces'; import { PlatformService } from '@ghostfolio/api/services/platform/platform.service';
import { permissions } from '@ghostfolio/common/permissions'; import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos';
import {
PlatformResponse,
PlatformsResponse
} from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import { Controller, Get, UseGuards } from '@nestjs/common'; import {
Body,
Controller,
Delete,
Get,
HttpException,
Inject,
Param,
Post,
Put,
UseGuards
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { pick } from 'lodash-es';
@AllowDuringImpersonation()
@Controller('platforms') @Controller('platforms')
export class PlatformsController { export class PlatformsController {
public constructor(private readonly platformService: PlatformService) {} public constructor(
private readonly platformService: PlatformService,
@Inject(REQUEST) private readonly request: RequestWithUser
) {}
@HasPermission(permissions.createPlatform)
@Post()
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async createPlatform(
@Body() data: CreatePlatformDto
): Promise<PlatformResponse> {
const platform = await this.platformService.createPlatform(data);
return pick(platform, ['id', 'name', 'url']);
}
@Delete(':id')
@HasPermission(permissions.deletePlatform)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async deletePlatform(@Param('id') id: string): Promise<void> {
const originalPlatform = await this.platformService.getPlatform({
id
});
if (!originalPlatform) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
await this.platformService.deletePlatform({ id });
}
@Get() @Get()
@HasPermission(permissions.readPlatforms) @HasPermission(permissions.readPlatforms)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getPlatforms(): Promise<PlatformsResponse> { public async getPlatforms(): Promise<PlatformsResponse> {
if (
hasPermission(
this.request.user.permissions,
permissions.readPlatformsWithAccountCount
)
) {
const platformsWithAccountCount =
await this.platformService.getPlatformsWithAccountCount({
orderBy: { name: 'asc' }
});
return { platforms: platformsWithAccountCount };
}
const platforms = await this.platformService.getPlatforms({ const platforms = await this.platformService.getPlatforms({
orderBy: { name: 'asc' } orderBy: { name: 'asc' }
}); });
return { platforms }; return {
platforms: platforms.map((platform) => {
return pick(platform, ['id', 'name', 'url']);
})
};
}
@HasPermission(permissions.updatePlatform)
@Put(':id')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async updatePlatform(
@Param('id') id: string,
@Body() data: UpdatePlatformDto
): Promise<PlatformResponse> {
const originalPlatform = await this.platformService.getPlatform({
id
});
if (!originalPlatform) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const platform = await this.platformService.updatePlatform({
data: {
...data
},
where: {
id
}
});
return pick(platform, ['id', 'name', 'url']);
} }
} }

5
apps/api/src/app/endpoints/platforms/platforms.module.ts

@ -1,11 +1,12 @@
import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module'; import { PlatformModule } from '@ghostfolio/api/services/platform/platform.module';
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { PlatformController } from './platform.controller';
import { PlatformsController } from './platforms.controller'; import { PlatformsController } from './platforms.controller';
@Module({ @Module({
controllers: [PlatformsController], controllers: [PlatformController, PlatformsController],
imports: [PlatformModule] imports: [PlatformModule]
}) })
export class PlatformsModule {} export class PlatformsModule {}

2
apps/api/src/app/import/import.module.ts

@ -1,7 +1,6 @@
import { AccountModule } from '@ghostfolio/api/app/account/account.module'; import { AccountModule } from '@ghostfolio/api/app/account/account.module';
import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { CacheModule } from '@ghostfolio/api/app/cache/cache.module'; import { CacheModule } from '@ghostfolio/api/app/cache/cache.module';
import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module';
import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module'; import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module';
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module';
@ -10,6 +9,7 @@ import { ConfigurationModule } from '@ghostfolio/api/services/configuration/conf
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.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 { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PlatformModule } from '@ghostfolio/api/services/platform/platform.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { DataGatheringQueueModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { DataGatheringQueueModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module';
import { RedisCacheModule } from '@ghostfolio/api/services/redis-cache/redis-cache.module'; import { RedisCacheModule } from '@ghostfolio/api/services/redis-cache/redis-cache.module';

2
apps/api/src/app/import/import.service.ts

@ -1,6 +1,5 @@
import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { PlatformService } from '@ghostfolio/api/app/platform/platform.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { getTagsWithDraftTag } from '@ghostfolio/api/helper/activity.helper'; import { getTagsWithDraftTag } from '@ghostfolio/api/helper/activity.helper';
import { getMaskedGhostfolioDataSource } from '@ghostfolio/api/helper/data-source.helper'; import { getMaskedGhostfolioDataSource } from '@ghostfolio/api/helper/data-source.helper';
@ -9,6 +8,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { PlatformService } from '@ghostfolio/api/services/platform/platform.service';
import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service';

2
apps/api/src/app/info/info.module.ts

@ -1,4 +1,3 @@
import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module';
import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module'; import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module'; import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module';
@ -7,6 +6,7 @@ import { ConfigurationModule } from '@ghostfolio/api/services/configuration/conf
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.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 { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PlatformModule } from '@ghostfolio/api/services/platform/platform.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { DataGatheringQueueModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { DataGatheringQueueModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module';
import { RedisCacheModule } from '@ghostfolio/api/services/redis-cache/redis-cache.module'; import { RedisCacheModule } from '@ghostfolio/api/services/redis-cache/redis-cache.module';

2
apps/api/src/app/platform/platform.module.ts → apps/api/src/services/platform/platform.module.ts

@ -2,11 +2,9 @@ import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { PlatformController } from './platform.controller';
import { PlatformService } from './platform.service'; import { PlatformService } from './platform.service';
@Module({ @Module({
controllers: [PlatformController],
exports: [PlatformService], exports: [PlatformService],
imports: [PrismaModule], imports: [PrismaModule],
providers: [PlatformService] providers: [PlatformService]

7
apps/api/src/app/platform/platform.service.ts → apps/api/src/services/platform/platform.service.ts

@ -49,9 +49,14 @@ export class PlatformService {
}); });
} }
public async getPlatformsWithAccountCount() { public async getPlatformsWithAccountCount({
orderBy
}: {
orderBy?: Prisma.PlatformOrderByWithRelationInput;
} = {}) {
const platformsWithAccountCount = const platformsWithAccountCount =
await this.prismaService.platform.findMany({ await this.prismaService.platform.findMany({
orderBy,
include: { include: {
_count: { _count: {
select: { accounts: true } select: { accounts: true }

20
apps/client/src/app/components/admin-platform/admin-platform.component.ts

@ -3,10 +3,11 @@ import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos'; import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos';
import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { ConfirmationDialogType } from '@ghostfolio/common/enums';
import { getLocale, getLowercase } from '@ghostfolio/common/helper'; import { getLocale, getLowercase } from '@ghostfolio/common/helper';
import { PlatformsResponse } from '@ghostfolio/common/interfaces';
import type { Platform } from '@ghostfolio/prisma/browser'; import type { Platform } from '@ghostfolio/prisma/browser';
import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo';
import { NotificationService } from '@ghostfolio/ui/notifications'; import { NotificationService } from '@ghostfolio/ui/notifications';
import { AdminService, DataService } from '@ghostfolio/ui/services'; import { DataService } from '@ghostfolio/ui/services';
import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfValueComponent } from '@ghostfolio/ui/value';
import { import {
@ -62,7 +63,9 @@ import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform-
export class GfAdminPlatformComponent implements OnInit { export class GfAdminPlatformComponent implements OnInit {
public readonly locale = input(getLocale()); public readonly locale = input(getLocale());
protected dataSource = new MatTableDataSource<Platform>(); protected dataSource = new MatTableDataSource<
PlatformsResponse['platforms'][0]
>();
protected readonly displayedColumns = [ protected readonly displayedColumns = [
'icon', 'icon',
@ -74,7 +77,7 @@ export class GfAdminPlatformComponent implements OnInit {
protected isLoading = false; protected isLoading = false;
protected readonly pageSize = DEFAULT_PAGE_SIZE; protected readonly pageSize = DEFAULT_PAGE_SIZE;
protected platforms: Platform[]; protected platforms: PlatformsResponse['platforms'];
private readonly deviceType = computed( private readonly deviceType = computed(
() => this.deviceDetectorService.deviceInfo().deviceType () => this.deviceDetectorService.deviceInfo().deviceType
@ -83,7 +86,6 @@ export class GfAdminPlatformComponent implements OnInit {
private readonly paginator = viewChild.required(MatPaginator); private readonly paginator = viewChild.required(MatPaginator);
private readonly sort = viewChild.required(MatSort); private readonly sort = viewChild.required(MatSort);
private readonly adminService = inject(AdminService);
private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly dataService = inject(DataService); private readonly dataService = inject(DataService);
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
@ -139,7 +141,7 @@ export class GfAdminPlatformComponent implements OnInit {
} }
private deletePlatform(aId: string) { private deletePlatform(aId: string) {
this.adminService this.dataService
.deletePlatform(aId) .deletePlatform(aId)
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({ .subscribe({
@ -157,10 +159,10 @@ export class GfAdminPlatformComponent implements OnInit {
private fetchPlatforms() { private fetchPlatforms() {
this.isLoading = true; this.isLoading = true;
this.adminService this.dataService
.fetchPlatforms() .fetchPlatforms()
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((platforms) => { .subscribe(({ platforms }) => {
this.platforms = platforms; this.platforms = platforms;
this.dataSource = new MatTableDataSource(platforms); this.dataSource = new MatTableDataSource(platforms);
@ -191,7 +193,7 @@ export class GfAdminPlatformComponent implements OnInit {
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((platform: CreatePlatformDto | null) => { .subscribe((platform: CreatePlatformDto | null) => {
if (platform) { if (platform) {
this.adminService this.dataService
.postPlatform(platform) .postPlatform(platform)
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({ .subscribe({
@ -231,7 +233,7 @@ export class GfAdminPlatformComponent implements OnInit {
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((platform: UpdatePlatformDto | null) => { .subscribe((platform: UpdatePlatformDto | null) => {
if (platform) { if (platform) {
this.adminService this.dataService
.putPlatform(platform) .putPlatform(platform)
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({ .subscribe({

2
libs/common/src/lib/interfaces/index.ts

@ -75,6 +75,7 @@ import type { LivenessHealthResponse } from './responses/liveness-health-respons
import type { LookupResponse } from './responses/lookup-response.interface'; import type { LookupResponse } from './responses/lookup-response.interface';
import type { MarketDataOfMarketsResponse } from './responses/market-data-of-markets-response.interface'; import type { MarketDataOfMarketsResponse } from './responses/market-data-of-markets-response.interface';
import type { OAuthResponse } from './responses/oauth-response.interface'; import type { OAuthResponse } from './responses/oauth-response.interface';
import type { PlatformResponse } from './responses/platform-response.interface';
import type { PlatformsResponse } from './responses/platforms-response.interface'; import type { PlatformsResponse } from './responses/platforms-response.interface';
import type { PortfolioDividendsResponse } from './responses/portfolio-dividends-response.interface'; import type { PortfolioDividendsResponse } from './responses/portfolio-dividends-response.interface';
import type { PortfolioHoldingResponse } from './responses/portfolio-holding-response.interface'; import type { PortfolioHoldingResponse } from './responses/portfolio-holding-response.interface';
@ -170,6 +171,7 @@ export {
MarketDataOfMarketsResponse, MarketDataOfMarketsResponse,
NullableLineChartItem, NullableLineChartItem,
OAuthResponse, OAuthResponse,
PlatformResponse,
PlatformsResponse, PlatformsResponse,
PortfolioChart, PortfolioChart,
PortfolioDetails, PortfolioDetails,

6
libs/common/src/lib/interfaces/responses/platform-response.interface.ts

@ -0,0 +1,6 @@
import type { Platform } from '@ghostfolio/prisma/browser';
export interface PlatformResponse extends Pick<
Platform,
'id' | 'name' | 'url'
> {}

4
libs/common/src/lib/interfaces/responses/platforms-response.interface.ts

@ -1,5 +1,5 @@
import type { Platform } from '@ghostfolio/prisma/browser'; import type { PlatformResponse } from './platform-response.interface';
export interface PlatformsResponse { export interface PlatformsResponse {
platforms: Platform[]; platforms: (PlatformResponse & { accountCount?: number })[];
} }

29
libs/ui/src/lib/services/admin.service.ts

@ -5,10 +5,8 @@ import {
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { import {
CreateAssetProfileSplitDto, CreateAssetProfileSplitDto,
CreatePlatformDto,
MergeAssetProfileDto, MergeAssetProfileDto,
UpdateAssetProfileDto, UpdateAssetProfileDto
UpdatePlatformDto
} from '@ghostfolio/common/dtos'; } from '@ghostfolio/common/dtos';
import { import {
AdminData, AdminData,
@ -21,11 +19,7 @@ import {
EnhancedAssetProfile EnhancedAssetProfile
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types'; import { DateRange } from '@ghostfolio/common/types';
import type { import type { AssetProfileSplit, MarketData } from '@ghostfolio/prisma/browser';
AssetProfileSplit,
MarketData,
Platform
} from '@ghostfolio/prisma/browser';
import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment'; import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
@ -61,10 +55,6 @@ export class AdminService {
}); });
} }
public deletePlatform(aId: string) {
return this.http.delete<void>(`/api/v1/platform/${aId}`);
}
public deleteAssetProfileSplit({ public deleteAssetProfileSplit({
dataSource, dataSource,
id, id,
@ -113,10 +103,6 @@ export class AdminService {
}); });
} }
public fetchPlatforms() {
return this.http.get<Platform[]>('/api/v1/platform');
}
public fetchUserById(id: string) { public fetchUserById(id: string) {
return this.http.get<AdminUserResponse>(`/api/v1/admin/user/${id}`); return this.http.get<AdminUserResponse>(`/api/v1/admin/user/${id}`);
} }
@ -252,17 +238,6 @@ export class AdminService {
); );
} }
public postPlatform(aPlatform: CreatePlatformDto) {
return this.http.post<Platform>(`/api/v1/platform`, aPlatform);
}
public putPlatform(aPlatform: UpdatePlatformDto) {
return this.http.put<Platform>(
`/api/v1/platform/${aPlatform.id}`,
aPlatform
);
}
public syncDemoUserAccount() { public syncDemoUserAccount() {
return this.http.get<void>(`/api/v1/admin/demo-user/sync`); return this.http.get<void>(`/api/v1/admin/demo-user/sync`);
} }

18
libs/ui/src/lib/services/data.service.ts

@ -3,6 +3,7 @@ import {
CreateAccountBalanceDto, CreateAccountBalanceDto,
CreateAccountDto, CreateAccountDto,
CreateOrderDto, CreateOrderDto,
CreatePlatformDto,
CreateTagDto, CreateTagDto,
CreateUserDto, CreateUserDto,
CreateWatchlistItemDto, CreateWatchlistItemDto,
@ -13,6 +14,7 @@ import {
UpdateBulkMarketDataDto, UpdateBulkMarketDataDto,
UpdateOrderDto, UpdateOrderDto,
UpdateOwnAccessTokenDto, UpdateOwnAccessTokenDto,
UpdatePlatformDto,
UpdatePropertyDto, UpdatePropertyDto,
UpdateTagDto, UpdateTagDto,
UpdateUserSettingDto UpdateUserSettingDto
@ -46,6 +48,7 @@ import {
LookupResponse, LookupResponse,
MarketDataOfMarketsResponse, MarketDataOfMarketsResponse,
OAuthResponse, OAuthResponse,
PlatformResponse,
PlatformsResponse, PlatformsResponse,
PortfolioDetails, PortfolioDetails,
PortfolioDividendsResponse, PortfolioDividendsResponse,
@ -366,6 +369,10 @@ export class DataService {
return this.http.delete<UserModel>(`/api/v1/user`, { body: aData }); return this.http.delete<UserModel>(`/api/v1/user`, { body: aData });
} }
public deletePlatform(aId: string) {
return this.http.delete<void>(`/api/v1/platforms/${aId}`);
}
public deleteTag(aId: string) { public deleteTag(aId: string) {
return this.http.delete<Tag>(`/api/v1/tags/${aId}`); return this.http.delete<Tag>(`/api/v1/tags/${aId}`);
} }
@ -914,6 +921,10 @@ export class DataService {
return this.http.post<MarketData>(url, marketData); return this.http.post<MarketData>(url, marketData);
} }
public postPlatform(aPlatform: CreatePlatformDto) {
return this.http.post<PlatformResponse>(`/api/v1/platforms`, aPlatform);
}
public postTag(aTag: CreateTagDto) { public postTag(aTag: CreateTagDto) {
return this.http.post<Tag>(`/api/v1/tags`, aTag); return this.http.post<Tag>(`/api/v1/tags`, aTag);
} }
@ -953,6 +964,13 @@ export class DataService {
); );
} }
public putPlatform(aPlatform: UpdatePlatformDto) {
return this.http.put<PlatformResponse>(
`/api/v1/platforms/${aPlatform.id}`,
aPlatform
);
}
public putTag(aTag: UpdateTagDto) { public putTag(aTag: UpdateTagDto) {
return this.http.put<Tag>(`/api/v1/tags/${aTag.id}`, aTag); return this.http.put<Tag>(`/api/v1/tags/${aTag.id}`, aTag);
} }

Loading…
Cancel
Save