diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 2419b0a7d..7ed7f364b 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -17,6 +17,7 @@ import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { AdminData, AdminMarketData, + AdminUserResponse, AdminUsersResponse, EnhancedSymbolProfile, ScraperConfiguration @@ -321,4 +322,11 @@ export class AdminController { take: isNaN(take) ? undefined : take }); } + + @Get('user/:id') + @HasPermission(permissions.accessAdminControl) + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async getUser(@Param('id') id: string): Promise { + return this.adminService.getUser(id); + } } diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 683e72cb8..57c471a18 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -23,6 +23,7 @@ import { AdminMarketData, AdminMarketDataDetails, AdminMarketDataItem, + AdminUserResponse, AdminUsersResponse, AssetProfileIdentifier, EnhancedSymbolProfile, @@ -35,7 +36,8 @@ import { BadRequestException, HttpException, Injectable, - Logger + Logger, + NotFoundException } from '@nestjs/common'; import { AssetClass, @@ -522,6 +524,73 @@ export class AdminService { return { count, users }; } + public async getUser(id: string): Promise { + const user = await this.prismaService.user.findUnique({ + where: { id }, + select: { + id: true, + role: true, + provider: true, + createdAt: true, + updatedAt: true, + analytics: { + select: { + activityCount: true, + country: true, + dataProviderGhostfolioDailyRequests: true, + updatedAt: true + } + }, + _count: { + select: { + accounts: true, + activities: true, + watchlist: true + } + }, + subscriptions: { + orderBy: { expiresAt: 'desc' }, + take: 3, + select: { + id: true, + expiresAt: true, + createdAt: true + } + }, + tags: { + select: { + id: true, + name: true + } + } + } + }); + + if (!user) { + throw new NotFoundException(`User with ID ${id} not found`); + } + + const { _count, analytics, createdAt, id: userId, role, provider } = user; + + return { + id: userId, + role, + provider, + createdAt, + updatedAt: user.updatedAt, + accountCount: _count.accounts || 0, + activityCount: _count.activities || 0, + watchlistCount: _count.watchlist || 0, + analytics: { + country: analytics?.country, + dailyApiRequests: analytics?.dataProviderGhostfolioDailyRequests || 0, + lastActivity: analytics?.updatedAt + }, + subscriptions: user.subscriptions, + tags: user.tags + }; + } + public async patchAssetProfileData( { dataSource, symbol }: AssetProfileIdentifier, {