diff --git a/src/activities/dtos/find-activities.input.ts b/src/activities/dtos/find-activities.input.ts index 56f9bb1..253cd34 100644 --- a/src/activities/dtos/find-activities.input.ts +++ b/src/activities/dtos/find-activities.input.ts @@ -18,6 +18,10 @@ export class FindActivitiesInput { @IsOptional() type?: ActivityType[]; + @Field(() => [String], { nullable: true }) + @IsOptional() + activityTypes?: string[]; + @Field({ nullable: true }) @IsOptional() dateFrom?: Date; diff --git a/src/activities/resolvers/activities.resolver.ts b/src/activities/resolvers/activities.resolver.ts index e92df9a..cde376b 100644 --- a/src/activities/resolvers/activities.resolver.ts +++ b/src/activities/resolvers/activities.resolver.ts @@ -38,6 +38,7 @@ import { } from '../../core/interceptors/data-loader.interceptor'; import { UserLoader } from '../../users/loaders/user.loader'; import DataLoader from 'dataloader'; +import { StatsActivities } from '../utils/stats-activities.class'; @Resolver(() => Activity) @UseInterceptors(DataLoaderInterceptor) @@ -60,6 +61,19 @@ export class ActivitiesResolver { return this.activitiesService.paginate(input, currentUser); } + @UseGuards(UserAuthGuard) + @Query(() => [StatsActivities]) + myActivitiesStatistics( + @CurrentUser() currentUser: User, + @Args('input', { nullable: true }) input: FindActivitiesInput = {}, + @Info() info: GraphQLResolveInfo, + ) { + info.cacheControl.setCacheHint({ scope: CacheScope.Private }); + input.userId = currentUser.id; + + return this.activitiesService.getStats(input, currentUser); + } + @UseGuards(UserAuthGuard) @Query(() => Activity) @UseFilters(NotFoundFilter) diff --git a/src/activities/resolvers/activity-routes.resolver.ts b/src/activities/resolvers/activity-routes.resolver.ts index 7203c65..f0f0c41 100644 --- a/src/activities/resolvers/activity-routes.resolver.ts +++ b/src/activities/resolvers/activity-routes.resolver.ts @@ -34,7 +34,7 @@ import { Activity } from '../entities/activity.entity'; import { ActivityLoader } from '../loaders/activity.loader'; import { ActivityRoutesService } from '../services/activity-routes.service'; import { PaginatedActivityRoutes } from '../utils/paginated-activity-routes.class'; -import { StatsActivities } from '../utils/stats-activities.class'; +import { StatsRoutes } from '../utils/stats-routes.class'; import { GraphQLResolveInfo } from 'graphql'; import { CacheScope } from 'apollo-server-types'; import { CreateActivityRouteInput } from '../dtos/create-activity-route.input'; @@ -117,8 +117,8 @@ export class ActivityRoutesResolver { } @UseGuards(UserAuthGuard) - @Query(() => [StatsActivities]) - myActivityStatistics( + @Query(() => [StatsRoutes]) + myRoutesStatistics( @CurrentUser() currentUser: User, @Args('input', { nullable: true }) input: FindActivityRoutesInput = {}, @Info() info: GraphQLResolveInfo, diff --git a/src/activities/services/activities.service.ts b/src/activities/services/activities.service.ts index 7c349c2..6e3088a 100644 --- a/src/activities/services/activities.service.ts +++ b/src/activities/services/activities.service.ts @@ -17,6 +17,7 @@ import { setBuilderCache } from '../../core/utils/entity-cache/entity-cache-help import { getPublishStatusParams } from '../../core/utils/contributable-helpers'; import { InjectQueue } from '@nestjs/bull'; import { Queue } from 'bull'; +import { StatsActivities } from '../utils/stats-activities.class'; @Injectable() export class ActivitiesService { @@ -214,6 +215,41 @@ export class ActivitiesService { }); } + async getStats( + params: FindActivitiesInput = {}, + currentUser: User = null, + ): Promise { + + const builder = this.activitiesRepository + .createQueryBuilder('ac') + .select('EXTRACT(YEAR FROM ac.date)', 'year') + .addSelect('ac.type', 'activity_type') + .addSelect('count(*)', 'nr_activities') + .where('ac.user_id = :userId', { + userId: currentUser.id, + }) + + .groupBy('EXTRACT(YEAR FROM ac.date)') + .addGroupBy('ac.type') + .orderBy('year', 'ASC'); + + if (params.activityTypes != null) { + builder.andWhere('ac.type_id IN(:...activityTypes)', { + routeTypes: params.activityTypes, + }); + } + const raw = await builder.getRawMany(); + const myStats = raw.map((element) => { + return { + year: element.year, + nr_activities: element.nr_activities, + type: element.activity_type, + } as StatsActivities; + }); + return myStats; + + } + async find(params: FindActivitiesInput = {}): Promise { return (await this.buildQuery(params)).getMany(); } diff --git a/src/activities/services/activity-routes.service.ts b/src/activities/services/activity-routes.service.ts index bcc2f96..707cdf9 100644 --- a/src/activities/services/activity-routes.service.ts +++ b/src/activities/services/activity-routes.service.ts @@ -44,7 +44,7 @@ import { calculateScore, recalculateActivityRoutesScores, } from '../../crags/utils/calculate-scores'; -import { StatsActivities } from '../utils/stats-activities.class'; +import { StatsRoutes } from '../utils/stats-routes.class'; @Injectable() export class ActivityRoutesService { @@ -510,7 +510,7 @@ export class ActivityRoutesService { async getStats( params: FindActivityRoutesInput = {}, currentUser: User = null, - ): Promise { + ): Promise { const builder = this.activityRoutesRepository .createQueryBuilder('ar') .select('EXTRACT(YEAR FROM ar.date)', 'year') @@ -524,9 +524,6 @@ export class ActivityRoutesService { .where('ar.user_id = :userId', { userId: currentUser.id, }) - .andWhere('ar.ascent_type IN (:...ascentType)', { - ascentType: ['onsight', 'redpoint', 'flash'], - }) .andWhere( "(r.publish_status IN ('published', 'in_review') OR (r.publish_status = 'draft' AND ar.user_id = :userId))", { userId: currentUser.id }, @@ -536,7 +533,7 @@ export class ActivityRoutesService { .addGroupBy('r.difficulty') .addGroupBy('EXTRACT(YEAR FROM ar.date)') .addGroupBy('ar.ascent_type') - .orderBy('coalesce(p.difficulty, r.difficulty)', 'ASC') + .orderBy('coalesce(p.difficulty, r.difficulty)', 'DESC') .addOrderBy('year', 'ASC'); if (params.routeTypes != null) { diff --git a/src/activities/utils/stats-activities.class.ts b/src/activities/utils/stats-activities.class.ts index bf05128..61c0dfd 100644 --- a/src/activities/utils/stats-activities.class.ts +++ b/src/activities/utils/stats-activities.class.ts @@ -1,17 +1,14 @@ -import { Field, Float, Int, ObjectType } from '@nestjs/graphql'; +import { Field, Int, ObjectType } from '@nestjs/graphql'; @ObjectType() export class StatsActivities { @Field(() => Int) year: number; - @Field(() => Float) - difficulty: number; + @Field(() => Int) + nr_activities: number; @Field(() => String) - ascent_type: string; - - @Field(() => Int) - nr_routes: number; + type: string; } diff --git a/src/activities/utils/stats-routes.class.ts b/src/activities/utils/stats-routes.class.ts new file mode 100644 index 0000000..0396108 --- /dev/null +++ b/src/activities/utils/stats-routes.class.ts @@ -0,0 +1,17 @@ +import { Field, Float, Int, ObjectType } from '@nestjs/graphql'; + +@ObjectType() +export class StatsRoutes { + @Field(() => Int) + year: number; + + @Field(() => Float) + difficulty: number; + + @Field(() => String) + ascent_type: string; + + @Field(() => Int) + nr_routes: number; + +}