diff --git a/apps/api/src/app/user/user.controller.ts b/apps/api/src/app/user/user.controller.ts index 5614733d2..6346ce43a 100644 --- a/apps/api/src/app/user/user.controller.ts +++ b/apps/api/src/app/user/user.controller.ts @@ -1,5 +1,6 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; +import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; @@ -30,7 +31,8 @@ import { Param, Post, Put, - UseGuards + UseGuards, + UseInterceptors } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { JwtService } from '@nestjs/jwt'; @@ -110,6 +112,7 @@ export class UserController { @Get() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseInterceptors(RedactValuesInResponseInterceptor) public async getUser( @Headers('accept-language') acceptLanguage: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string @@ -117,11 +120,11 @@ export class UserController { const impersonationUserId = await this.impersonationService.validateImpersonationId(impersonationId); - return this.userService.getUser( - this.request.user, + return this.userService.getUser({ impersonationUserId, - acceptLanguage?.split(',')?.[0] - ); + locale: acceptLanguage?.split(',')?.[0], + user: this.request.user + }); } @Post() diff --git a/apps/api/src/app/user/user.module.ts b/apps/api/src/app/user/user.module.ts index 66523dd42..7ca68d275 100644 --- a/apps/api/src/app/user/user.module.ts +++ b/apps/api/src/app/user/user.module.ts @@ -1,5 +1,6 @@ import { OrderModule } from '@ghostfolio/api/app/order/order.module'; import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module'; +import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { I18nModule } from '@ghostfolio/api/services/i18n/i18n.module'; import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; @@ -27,6 +28,7 @@ import { UserService } from './user.service'; OrderModule, PrismaModule, PropertyModule, + RedactValuesInResponseModule, SubscriptionModule, TagModule ], diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index c60f4f721..301ed221d 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -30,7 +30,7 @@ import { PROPERTY_IS_READ_ONLY_MODE, PROPERTY_SYSTEM_MESSAGE, TAG_ID_EXCLUDE_FROM_ANALYSIS, - locale + locale as defaultLocale } from '@ghostfolio/common/config'; import { User as IUser, @@ -96,11 +96,17 @@ export class UserService { return { accessToken, hashedAccessToken }; } - public async getUser( - { accounts, id, permissions, settings, subscription }: UserWithSettings, - impersonationUserId: string, - aLocale = locale - ): Promise { + public async getUser({ + impersonationUserId, + locale = defaultLocale, + user + }: { + impersonationUserId: string; + locale?: string; + user: UserWithSettings; + }): Promise { + const { id, permissions, settings, subscription } = user; + const userData = await Promise.all([ this.prismaService.access.findMany({ include: { @@ -114,23 +120,23 @@ export class UserService { name: 'asc' }, where: { - userId: impersonationUserId + userId: impersonationUserId || user.id } }), this.prismaService.order.count({ - where: { userId: id } + where: { userId: impersonationUserId || user.id } }), this.prismaService.order.findFirst({ orderBy: { date: 'asc' }, - where: { userId: id } + where: { userId: impersonationUserId || user.id } }), - this.tagService.getTagsForUser(id) + this.tagService.getTagsForUser(impersonationUserId || user.id) ]); const access = userData[0]; - const impersonationAccounts = userData[1]; + const accounts = userData[1]; const activitiesCount = userData[2]; const firstActivity = userData[3]; let tags = userData[4].filter((tag) => { @@ -169,11 +175,13 @@ export class UserService { permissions: accessItem.permissions }; }), - accounts: impersonationUserId ? impersonationAccounts : accounts, + accounts: sortBy(accounts, ({ name }) => { + return name.toLowerCase(); + }), dateOfFirstActivity: firstActivity?.date ?? new Date(), settings: { ...(settings.settings as UserSettings), - locale: (settings.settings as UserSettings)?.locale ?? aLocale + locale: (settings.settings as UserSettings)?.locale ?? locale } }; } diff --git a/apps/api/src/services/tag/tag.service.ts b/apps/api/src/services/tag/tag.service.ts index eb2d7bfef..f4cbd4cb1 100644 --- a/apps/api/src/services/tag/tag.service.ts +++ b/apps/api/src/services/tag/tag.service.ts @@ -75,12 +75,16 @@ export class TagService { } }); - return tags.map(({ _count, id, name, userId }) => ({ - id, - name, - userId, - isUsed: _count.activities > 0 - })); + return tags + .map(({ _count, id, name, userId }) => ({ + id, + name, + userId, + isUsed: _count.activities > 0 + })) + .sort((a, b) => { + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); + }); } public async getTagsWithActivityCount() {