Browse Source

Respect activity type and date range filter

pull/7492/head
Thomas Kaul 1 month ago
parent
commit
0cad8157b5
  1. 99
      apps/api/src/app/activities/activities.controller.ts
  2. 39
      apps/api/src/app/activities/delete-activities.dto.ts
  3. 27
      apps/api/src/app/activities/get-activities.dto.ts

99
apps/api/src/app/activities/activities.controller.ts

@ -18,7 +18,7 @@ import {
ActivityResponse
} from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import type { DateRange, RequestWithUser } from '@ghostfolio/common/types';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
@ -29,7 +29,6 @@ import {
HttpException,
Inject,
Param,
ParseIntPipe,
Post,
Put,
Query,
@ -38,11 +37,13 @@ import {
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { Order, Prisma, Type as ActivityType } from '@prisma/client';
import { Order } from '@prisma/client';
import { parseISO } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { ActivitiesService } from './activities.service';
import { DeleteActivitiesDto } from './delete-activities.dto';
import { GetActivitiesDto } from './get-activities.dto';
@Controller('activities')
export class ActivitiesController {
@ -60,36 +61,30 @@ export class ActivitiesController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
public async deleteActivities(
@Query('accounts') filterByAccounts?: string,
@Query('activityTypes') filterByTypes?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('range') dateRange?: DateRange,
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string
@Query() query: DeleteActivitiesDto
): Promise<number> {
let endDate: Date;
let startDate: Date;
if (dateRange) {
({ endDate, startDate } = getIntervalFromDateRange({ dateRange }));
if (query.range) {
({ endDate, startDate } = getIntervalFromDateRange({
dateRange: query.range
}));
}
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags
filterByAccounts: query.accounts,
filterByAssetClasses: query.assetClasses,
filterByDataSource: query.dataSource,
filterBySymbol: query.symbol,
filterByTags: query.tags
});
const types = this.parseActivityTypes(filterByTypes);
return this.activitiesService.deleteActivities({
endDate,
filters,
startDate,
types,
types: query.activityTypes,
userId: this.request.user.id
});
}
@ -122,51 +117,41 @@ export class ActivitiesController {
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getAllActivities(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string,
@Query('activityTypes') filterByTypes?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('range') dateRange?: DateRange,
@Query('skip', new ParseIntPipe({ optional: true })) skip?: number,
@Query('sortColumn') sortColumn?: string,
@Query('sortDirection') sortDirection?: Prisma.SortOrder,
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string,
@Query('take', new ParseIntPipe({ optional: true })) take?: number
@Query() query: GetActivitiesDto
): Promise<ActivitiesResponse> {
let endDate: Date;
let startDate: Date;
if (dateRange) {
({ endDate, startDate } = getIntervalFromDateRange({ dateRange }));
if (query.range) {
({ endDate, startDate } = getIntervalFromDateRange({
dateRange: query.range
}));
}
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags
filterByAccounts: query.accounts,
filterByAssetClasses: query.assetClasses,
filterByDataSource: query.dataSource,
filterBySymbol: query.symbol,
filterByTags: query.tags
});
const impersonationUserId =
await this.impersonationService.validateImpersonationId(impersonationId);
const types = this.parseActivityTypes(filterByTypes);
const userCurrency = this.request.user.settings.settings.baseCurrency;
const { activities, count } = await this.activitiesService.getActivities({
endDate,
filters,
skip,
sortColumn,
sortDirection,
startDate,
take,
types,
userCurrency,
includeDrafts: true,
skip: query.skip,
sortColumn: query.sortColumn,
sortDirection: query.sortDirection,
take: query.take,
types: query.activityTypes,
userId: impersonationUserId || this.request.user.id,
withExcludedAccountsAndActivities: true
});
@ -360,28 +345,4 @@ export class ActivitiesController {
}
});
}
private parseActivityTypes(filterByTypes?: string): ActivityType[] {
if (!filterByTypes) {
return [];
}
const types = filterByTypes.split(',');
const invalidTypes = types.filter((type) => {
return !Object.values(ActivityType).includes(type as ActivityType);
});
if (invalidTypes.length > 0) {
throw new HttpException(
{
error: getReasonPhrase(StatusCodes.BAD_REQUEST),
message: [`Invalid activity type: ${invalidTypes.join(', ')}`]
},
StatusCodes.BAD_REQUEST
);
}
return types as ActivityType[];
}
}

39
apps/api/src/app/activities/delete-activities.dto.ts

@ -0,0 +1,39 @@
import { DateRange } from '@ghostfolio/common/types';
import { Type as ActivityType } from '@prisma/client';
import { Transform, TransformFnParams } from 'class-transformer';
import { IsEnum, IsOptional, IsString } from 'class-validator';
import { isString } from 'lodash';
export class DeleteActivitiesDto {
@IsOptional()
@IsString()
accounts?: string;
@IsEnum(ActivityType, { each: true })
@IsOptional()
@Transform(({ value }: TransformFnParams) => {
return isString(value) ? value.split(',') : value;
})
activityTypes?: ActivityType[];
@IsOptional()
@IsString()
assetClasses?: string;
@IsOptional()
@IsString()
dataSource?: string;
@IsOptional()
@IsString()
range?: DateRange;
@IsOptional()
@IsString()
symbol?: string;
@IsOptional()
@IsString()
tags?: string;
}

27
apps/api/src/app/activities/get-activities.dto.ts

@ -0,0 +1,27 @@
import { Prisma } from '@prisma/client';
import { Type } from 'class-transformer';
import { IsIn, IsInt, IsOptional, IsString, Min } from 'class-validator';
import { DeleteActivitiesDto } from './delete-activities.dto';
export class GetActivitiesDto extends DeleteActivitiesDto {
@IsInt()
@IsOptional()
@Min(0)
@Type(() => Number)
skip?: number;
@IsOptional()
@IsString()
sortColumn?: string;
@IsIn(['asc', 'desc'] as Prisma.SortOrder[])
@IsOptional()
sortDirection?: Prisma.SortOrder;
@IsInt()
@IsOptional()
@Min(0)
@Type(() => Number)
take?: number;
}
Loading…
Cancel
Save