mirror of
https://github.com/apricote/Listory.git
synced 2026-02-06 17:57:03 +00:00
refactor(server): introduce TimePresets for reports
This commit is contained in:
parent
6f8fc0265a
commit
b8918889a1
5 changed files with 89 additions and 11 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
import { IsOptional, ValidateNested, IsISO8601 } from "class-validator";
|
import { IsDate, IsOptional, ValidateNested } from "class-validator";
|
||||||
|
import { Interval } from "date-fns";
|
||||||
import { User } from "src/users/user.entity";
|
import { User } from "src/users/user.entity";
|
||||||
|
|
||||||
// tslint:disable-next-line: max-classes-per-file
|
// tslint:disable-next-line: max-classes-per-file
|
||||||
export class GetListensFilterTimeDto {
|
export class GetListensFilterTimeDto implements Interval {
|
||||||
@IsISO8601()
|
@IsDate()
|
||||||
start: string;
|
start: Date;
|
||||||
@IsISO8601()
|
@IsDate()
|
||||||
end: string;
|
end: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line: max-classes-per-file
|
// tslint:disable-next-line: max-classes-per-file
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ export class ListensService {
|
||||||
queryBuilder = queryBuilder.andWhere(
|
queryBuilder = queryBuilder.andWhere(
|
||||||
"l.playedAt BETWEEN :timeStart AND :timeEnd",
|
"l.playedAt BETWEEN :timeStart AND :timeEnd",
|
||||||
{
|
{
|
||||||
timeStart: parseISO(filter.time.start),
|
timeStart: filter.time.start,
|
||||||
timeEnd: parseISO(filter.time.end),
|
timeEnd: filter.time.end,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
src/reports/interval.d.ts
vendored
Normal file
4
src/reports/interval.d.ts
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface Interval {
|
||||||
|
start: Date;
|
||||||
|
end: Date;
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,25 @@
|
||||||
import { Injectable } from "@nestjs/common";
|
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||||
import {
|
import {
|
||||||
eachDayOfInterval,
|
eachDayOfInterval,
|
||||||
eachMonthOfInterval,
|
eachMonthOfInterval,
|
||||||
eachWeekOfInterval,
|
eachWeekOfInterval,
|
||||||
eachYearOfInterval,
|
eachYearOfInterval,
|
||||||
|
endOfDay,
|
||||||
formatISO,
|
formatISO,
|
||||||
Interval,
|
|
||||||
isSameDay,
|
isSameDay,
|
||||||
isSameMonth,
|
isSameMonth,
|
||||||
isSameWeek,
|
isSameWeek,
|
||||||
isSameYear,
|
isSameYear,
|
||||||
parseISO,
|
parseISO,
|
||||||
|
parseJSON,
|
||||||
|
startOfDay,
|
||||||
|
sub,
|
||||||
} from "date-fns";
|
} from "date-fns";
|
||||||
import { ListensService } from "../listens/listens.service";
|
import { ListensService } from "../listens/listens.service";
|
||||||
import { GetListenReportDto } from "./dto/get-listen-report.dto";
|
import { GetListenReportDto } from "./dto/get-listen-report.dto";
|
||||||
import { ListenReportDto } from "./dto/listen-report.dto";
|
import { ListenReportDto } from "./dto/listen-report.dto";
|
||||||
import { Timeframe } from "./timeframe.enum";
|
import { Timeframe } from "./timeframe.enum";
|
||||||
|
import { TimePreset } from "./timePreset.enum";
|
||||||
|
|
||||||
const timeframeToDateFns: {
|
const timeframeToDateFns: {
|
||||||
[x in Timeframe]: {
|
[x in Timeframe]: {
|
||||||
|
|
@ -41,6 +45,16 @@ const timeframeToDateFns: {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const timePresetToDays: { [x in TimePreset]: number } = {
|
||||||
|
[TimePreset.LAST_7_DAYS]: 7,
|
||||||
|
[TimePreset.LAST_30_DAYS]: 30,
|
||||||
|
[TimePreset.LAST_90_DAYS]: 90,
|
||||||
|
[TimePreset.LAST_180_DAYS]: 180,
|
||||||
|
[TimePreset.LAST_365_DAYS]: 365,
|
||||||
|
[TimePreset.ALL_TIME]: 0, // Not used for this
|
||||||
|
[TimePreset.CUSTOM]: 0, // Not used for this
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ReportsService {
|
export class ReportsService {
|
||||||
constructor(private readonly listensService: ListensService) {}
|
constructor(private readonly listensService: ListensService) {}
|
||||||
|
|
@ -48,9 +62,16 @@ export class ReportsService {
|
||||||
async getListens(options: GetListenReportDto): Promise<ListenReportDto> {
|
async getListens(options: GetListenReportDto): Promise<ListenReportDto> {
|
||||||
const { user, timeFrame, timeStart, timeEnd } = options;
|
const { user, timeFrame, timeStart, timeEnd } = options;
|
||||||
|
|
||||||
|
// Function should eventually be rewritten to accept a timepreset
|
||||||
|
const interval = this.getIntervalFromPreset({
|
||||||
|
timePreset: TimePreset.CUSTOM,
|
||||||
|
customTimeStart: timeStart,
|
||||||
|
customTimeEnd: timeEnd,
|
||||||
|
});
|
||||||
|
|
||||||
const { items: listens } = await this.listensService.getListens({
|
const { items: listens } = await this.listensService.getListens({
|
||||||
user,
|
user,
|
||||||
filter: { time: { start: timeStart, end: timeEnd } },
|
filter: { time: interval },
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 10000000,
|
limit: 10000000,
|
||||||
});
|
});
|
||||||
|
|
@ -70,4 +91,47 @@ export class ReportsService {
|
||||||
|
|
||||||
return { items: reportItems, timeStart, timeEnd, timeFrame };
|
return { items: reportItems, timeStart, timeEnd, timeFrame };
|
||||||
}
|
}
|
||||||
|
private getIntervalFromPreset(options: {
|
||||||
|
timePreset: TimePreset;
|
||||||
|
customTimeStart?: string;
|
||||||
|
customTimeEnd?: string;
|
||||||
|
}): Interval {
|
||||||
|
let interval = {
|
||||||
|
start: startOfDay(new Date()),
|
||||||
|
end: endOfDay(new Date()), // NOW
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (options.timePreset) {
|
||||||
|
case TimePreset.LAST_7_DAYS:
|
||||||
|
case TimePreset.LAST_30_DAYS:
|
||||||
|
case TimePreset.LAST_90_DAYS:
|
||||||
|
case TimePreset.LAST_180_DAYS:
|
||||||
|
case TimePreset.LAST_365_DAYS: {
|
||||||
|
interval.start = startOfDay(
|
||||||
|
sub(interval.start, { days: timePresetToDays[options.timePreset] })
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TimePreset.ALL_TIME: {
|
||||||
|
interval.start = new Date(0); // Start of epoch
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TimePreset.CUSTOM: {
|
||||||
|
if (!options.customTimeStart && !options.customTimeEnd) {
|
||||||
|
throw new BadRequestException("MissingCustomTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
interval = {
|
||||||
|
start: parseJSON(options.customTimeStart),
|
||||||
|
end: parseJSON(options.customTimeEnd),
|
||||||
|
};
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
src/reports/timePreset.enum.ts
Normal file
9
src/reports/timePreset.enum.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
export enum TimePreset {
|
||||||
|
LAST_7_DAYS = "last_7_days",
|
||||||
|
LAST_30_DAYS = "last_30_days",
|
||||||
|
LAST_90_DAYS = "last_90_days",
|
||||||
|
LAST_180_DAYS = "last_180_days",
|
||||||
|
LAST_365_DAYS = "last_365_days",
|
||||||
|
ALL_TIME = "all_time",
|
||||||
|
CUSTOM = "custom",
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue