Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip contributing message service #338

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const config = {
gettingHiredChannelId: process.env.DISCORD_GETTING_HIRED_CHANNEL_ID,
botSpamPlaygroundChannelId: '513125912070455296',
FAQChannelId: '823266307293839401',
contributingOpportunitiesChannelId: '1012271881472192615',
},
roles: {
NOBOTRoleId: '783764176178774036',
Expand Down
7 changes: 7 additions & 0 deletions events/ready.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const { Events } = require('discord.js');
const { guildId } = require('../config');
const ContributeService = require('../services/contribute');
const config = require('../config');

module.exports = {
name: Events.ClientReady,
Expand All @@ -10,5 +12,10 @@ module.exports = {
// Fetch Guild members on startup to ensure the integrity of the cache
const guild = await client.guilds.fetch(guildId);
await guild.members.fetch();

new ContributeService(
client,
config.channels.contributingOpportunitiesChannelId,
).schedule();
},
};
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@discordjs/rest": "^1.7.1",
"axios": "^1.4.0",
"cron": "^2.3.1",
"discord-api-types": "^0.37.43",
"discord.js": "^14.11.0",
"dotenv": "^16.1.4",
Expand Down
88 changes: 88 additions & 0 deletions services/contribute/contribute.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const Redis = require('ioredis');
const { CronJob } = require('cron');

class ContributeService {
constructor(client, contributingChannelId) {
this.redis = new Redis(process.env.REDIS_URL);
this.client = client;
this.contributingChannelId = contributingChannelId;
}

tenDays = 864000000;

async schedule() {
const job = new CronJob(
'0 12 * * MON', // every Monday at 12:00 PM UTC
async () => {
await this.start();
},
null,
true,
'America/Los_Angeles',
);
job.start();
}

async start() {
const issues = (await ContributeService.fetchGoodFirstIssues()).map((i) => ({
id: i.id,
html_url: i.html_url,
}));
const filtered = await this.filterIssues(issues);
const issueToSend = ContributeService.issueToSend(issues, filtered);

if (issueToSend) {
await this.cacheIssue(issueToSend);
await this.sendMessage(`Hey everyone! We have a new **Good First Issue** available for you to work on! Check it out here: ${issueToSend.html_url}`);
} else {
await this.sendMessage('Hey everyone! We don\'t have any new **Good First Issues** available for you to work on right now. Check back later!');
}
}

static async fetchGoodFirstIssues() {
const response = await fetch('https://api.github.com/repos/theodinproject/curriculum/issues?labels=Type:%20Good%20First%20Issue');
const rawIssues = await response.json();
return rawIssues;
}

async sendMessage(message) {
const channel = this.client.channels.cache.get(this.contributingChannelId);
await channel.send(message);
}

static issueToSend(issues, filtered) {
if (issues.length === 0) {
return null;
}
if (filtered.length === 0) {
return issues[0];
}
return filtered[0];
}

async filterIssues(issues) {
const filtered = [];
// eslint-disable-next-line no-restricted-syntax
for (const issue of issues) {
// eslint-disable-next-line no-await-in-loop
const isCached = await this.isIssueCached(issue.id);
if (!isCached) {
filtered.push(issue);
}
}
return filtered;
}

async cacheIssue(issue) {
await this.redis.set(issue.id, issue.html_url, 'EX', this.tenDays);
}

async isIssueCached(issueId) {
const issue = await this.redis.get(issueId);
if (issue) return true;

return false;
}
}

module.exports = ContributeService;
3 changes: 3 additions & 0 deletions services/contribute/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const Contribute = require('./contribute.service');

module.exports = Contribute;