Skip to content

Commit

Permalink
feat: pass custom timeframe for the graph; closes: #87 and #208
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashutosh00710 committed May 19, 2024
1 parent 6a9d634 commit 5156b91
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ Customize the appearance of your Activity Graph however you want with URL params
| `radius` | border radius of graph | number (0-16 inclusive) |
| `height` | height of the graph | number (200-600 inclusive) |
| `days` | number of to days display on graph | number between (1 - 90) [Recommended below 40] |
| `from` | date from which the graph starts | format `YYYY-MM-DD` |
| `to` | date where the graph will end | format `YYYY-MM-DD` |

**For `custom_title` please make sure that you are using %20 for spaces**

Expand Down
22 changes: 17 additions & 5 deletions src/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,23 @@ export class Fetcher {
});
}

public async fetchContributions(days: number): Promise<UserDetails | string> {
const now = moment();
const from = moment(now).subtract(days, 'days').utc().toISOString();
// also include the next day in case our server is behind in time with respect to GitHub
const to = moment(now).add(1, 'days').utc().toISOString();
public async fetchContributions(
days: number,
customFromDate?: string,
customToDate?: string
): Promise<UserDetails | string> {
let from = '',
to = '';
if (customFromDate && customToDate) {
from = customFromDate;
to = moment(customToDate).add(2, 'days').utc().toISOString();
days += 1;
} else {
const now = moment();
from = moment(now).subtract(days, 'days').utc().toISOString();
// also include the next day in case our server is behind in time with respect to GitHub
to = moment(now).add(1, 'days').utc().toISOString();
}

try {
const apiResponse = await this.fetch(this.getGraphQLQuery(from, to));
Expand Down
7 changes: 6 additions & 1 deletion src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ export class Handlers {
const utils = new Utilities(req.query);

const fetcher = new Fetcher(utils.username);
const fetchCalendarData = await fetcher.fetchContributions(utils.queryOptions().days);
const queryOptions = utils.queryOptions();
const fetchCalendarData = await fetcher.fetchContributions(
utils.queryOptions().days,
queryOptions.from,
queryOptions.to
);

const { finalGraph, header } = await utils.buildGraph(fetchCalendarData);
utils.setHttpHeader(res, header.maxAge);
Expand Down
4 changes: 4 additions & 0 deletions src/interfaces/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export class QueryOption {
username: string;
hide_title?: boolean;
custom_title?: string;
from?: string;
to?: string;
colors: Colors;
area: boolean;
radius: number;
Expand All @@ -42,6 +44,8 @@ export class ParsedQs {
title_color?: string;
height?: number;
days?: string;
from?: string;
to?: string;
}

export class GraphArgs {
Expand Down
55 changes: 53 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import moment from 'moment';
import { Response } from 'express';
import { Card } from './GraphCards';
import { invalidUserSvg } from './svgs';
Expand Down Expand Up @@ -38,7 +39,7 @@ export class Utilities {
};
}

private validateDate(days?: string): number {
private validateDays(days?: string): number {
const d = Number(days);
if (typeof d !== 'number') {
return 31;
Expand All @@ -49,6 +50,38 @@ export class Utilities {
}
}

private validateDate(date?: string): boolean {
const format = 'YYYY-MM-DD';
return moment(date, format, true).isValid();
}

private stringDateToUTC(date?: string): string {
const format = 'YYYY-MM-DD';
return moment(date, format, true).utc().toISOString();
}

private validateFromIsLessThanTwo(from: string, to: string): boolean {
// Parse the ISO string dates into Moment objects
const fromDate = moment(from);
const toDate = moment(to);
const now = moment();
// Compare the dates using the isBefore method
return (
fromDate.isBefore(toDate) &&
moment(now).isSameOrBefore(fromDate) &&
moment(now).isSameOrBefore(toDate)
);
}

private calculateNumberOfDaysFromDate(from: string, to: string): number {
// Parse the ISO string dates into Moment objects
const fromDate = moment(from);
const toDate = moment(to);

// Compare the dates using the isBefore method
return toDate.diff(fromDate, 'days');
}

public queryOptions() {
let area = false;
if (String(this.queryString.area) === 'true') {
Expand All @@ -57,6 +90,22 @@ export class Utilities {

// Custom options for user
const colors = this.getColors();
let from = '',
to = '',
days = 31;
const isFromValid = this.validateDate(this.queryString.from);
const isToValid = this.validateDate(this.queryString.to);
if (isFromValid && isToValid) {
from = this.stringDateToUTC(this.queryString.from);
to = this.stringDateToUTC(this.queryString.to);
if (!this.validateFromIsLessThanTwo(from, to)) {
from = '';
to = '';
days = 31;
} else {
days = this.calculateNumberOfDaysFromDate(from, to);
}
}

const options: QueryOption = {
username: this.username,
Expand All @@ -69,7 +118,9 @@ export class Utilities {
height: this.queryString.height
? Math.min(Math.max(this.queryString.height, 200), 600)
: 420, // Custom height implementation from range [200, 600], if not specified use default value - 420
days: this.validateDate(this.queryString.days),
days: isFromValid && isToValid ? days : this.validateDays(this.queryString.days),
from,
to,
};

if (this.queryString.custom_title)
Expand Down

0 comments on commit 5156b91

Please sign in to comment.