Skip to content

Commit

Permalink
Add Promotions Schedule Reminder (#13)
Browse files Browse the repository at this point in the history
* #4: add urgent promotional reminder

* #4: add 24 hour urgency check and conditional message sending

* #4: run prettier
  • Loading branch information
l004p authored Jun 29, 2024
1 parent 0c1d28d commit aff7a6d
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/github/graphql/projectV2Items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ export const PROJECT_V2_ITEMS = `
}
}
}
... on ProjectV2ItemFieldLabelValue {
labels(first: 5) {
totalCount
nodes {
name
}
}
}
... on ProjectV2ItemFieldSingleSelectValue {
id
name
Expand Down
5 changes: 5 additions & 0 deletions src/github/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export interface ProjectV2Item {
url: string;
}[];
};
labels: {
nodes: {
name: string;
}[];
};
name: string;
}[];
};
Expand Down
29 changes: 29 additions & 0 deletions src/items/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface Item {
title: string;
status: string;
assignedUsers: string[];
labels?: string[];
dueDate?: Date;
url?: string;
}
Expand All @@ -16,6 +17,9 @@ export const convertGithubItems = (items: ProjectV2Item[]): Item[] => {
const status = item.fieldValues.nodes
.filter((field) => field.name)
.map((field) => field.name)[0];
const labels = item.fieldValues.nodes
.filter((field) => field.labels)
.flatMap((field) => field.labels.nodes.map((label) => label.name));

// TODO: improve this
let dueDate: Date | undefined;
Expand All @@ -28,6 +32,7 @@ export const convertGithubItems = (items: ProjectV2Item[]): Item[] => {
title: item.content.title,
url: item.content.url,
assignedUsers,
labels,
dueDate: dueDate,
status: status,
};
Expand Down Expand Up @@ -65,6 +70,24 @@ export const filterForUrgentItems = (items: Item[]) => {
});
};

//for reminders ran at 8:30pm (midnight in UTC) checking the next 24 hours will pull up tasks
//due the next day
export const filterForTwentyFourHours = (items: Item[]) => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);

return items.filter((item) => {
if (!item.dueDate) {
return false;
}
return (
item.dueDate <= tomorrow &&
item.status !== "Done" &&
item.assignedUsers.length !== 0
);
});
};

export const filterUpcomingItems = (items: Item[]) => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 2);
Expand Down Expand Up @@ -92,3 +115,9 @@ export const filterOutStatus = (items: Item[], status: string) => {
export const filterForUnassigned = (items: Item[]) => {
return items.filter((item) => item.assignedUsers.length === 0);
};

export const filterByLabel = (items: Item[], labels: string[]) => {
return items.filter((item) =>
labels.some((label) => item.labels?.includes(label)),
);
};
1 change: 1 addition & 0 deletions src/reminders/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { dueTodayReminder } from "./dueTodayReminder";
export { fullItemReportReminder } from "./fullItemReportReminder";
export { urgentPromotionReminder } from "./urgentPromotionReminder";
48 changes: 48 additions & 0 deletions src/reminders/urgentPromotionReminder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { sendDiscordItemMessage } from "../discord";
import { fetchProjectV2Items } from "../github";
import {
convertGithubItems,
filterByLabel,
filterForTwentyFourHours,
filterForUrgentItems,
filterOutStatus,
} from "../items";

export const urgentPromotionReminder = async () => {
const githubItemsResult = await fetchProjectV2Items();
if (githubItemsResult.err) {
return githubItemsResult;
}

const items = convertGithubItems(githubItemsResult.val);
const nonBacklogItems = filterOutStatus(items, "Backlog");
const urgentItems = filterForTwentyFourHours(nonBacklogItems);
const itemsWithLabels = filterByLabel(urgentItems, [
"discord announcement",
"social post",
"scs email",
]);

if (itemsWithLabels.length === 0) {
return null;
}

const message = {
title: "Urgent Promotional Items Reminder 📬‼️",
message:
"Check out all upcoming tasks [here.](https://github.com/orgs/CarletonComputerScienceSociety/projects/18) 🐀🐀",
sections: [
...(itemsWithLabels.length > 0
? [
{
title: "🔥 Urgent & Overdue",
items: itemsWithLabels,
},
]
: []),
],
};

const discordMessageResult = await sendDiscordItemMessage(message);
return discordMessageResult;
};
3 changes: 3 additions & 0 deletions test/items/factories/item-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ export const itemFactory = ({
title,
status,
assignedUsers,
labels,
dueDate,
url,
}: {
title?: string;
status?: string;
assignedUsers?: string[];
labels?: string[];
dueDate?: Date;
url?: string;
} = {}): Item => {
return {
title: title ?? "title",
status: status ?? "status",
assignedUsers: assignedUsers ?? ["https://github.com/MathyouMB"],
labels: labels ?? undefined,
dueDate: dueDate ?? undefined,
url: url ?? "https://github.com/MathyouMB",
};
Expand Down
38 changes: 38 additions & 0 deletions test/items/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { describe, expect } from "@jest/globals";
import {
filterByDateRange,
filterByLabel,
filterByStatus,
filterForTwentyFourHours,
filterForUnassigned,
filterForUrgentItems,
filterOutStatus,
filterUpcomingItems,
} from "../../src/items";
import { itemFactory } from "./factories/item-factory";
import exp from "constants";

describe("filterByStatus", () => {
it("will return items with the given status", () => {
Expand Down Expand Up @@ -98,6 +101,23 @@ describe("filterForUrgentItems", () => {
});
});

describe("filterForTwentyFourHours", () => {
it("will return items that are overdue or due in the next 24 Hours", () => {
const today = new Date();
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
const dayAfterTomorrow = new Date();
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 2);
const item1 = itemFactory({ dueDate: today });
const item2 = itemFactory({ dueDate: tomorrow });
const item3 = itemFactory({ dueDate: dayAfterTomorrow });

const result = filterForTwentyFourHours([item1, item2, item3]);

expect(result).toEqual([item1, item2]);
});
});

describe("filterUpcomingItems", () => {
it("will return items due after tomorrow", () => {
const today = new Date();
Expand All @@ -114,3 +134,21 @@ describe("filterUpcomingItems", () => {
expect(result).toEqual([item3]);
});
});

describe("filterByLabels", () => {
it("will return items with any of the labels matching", () => {
const item1 = itemFactory({ labels: [] });
const item2 = itemFactory({ labels: ["social post"] });
const item3 = itemFactory({ labels: ["social post", "not a label"] });
const item4 = itemFactory({ labels: ["social post", "scs email"] });
const item5 = itemFactory({ labels: ["scs email", "not a label"] });
const item6 = itemFactory({ labels: ["not a label 1", "not a label 2"] });

const result = filterByLabel(
[item1, item2, item3, item4, item5, item6],
["social post", "scs email"],
);

expect(result).toEqual([item2, item3, item4, item5]);
});
});

0 comments on commit aff7a6d

Please sign in to comment.