mirror of
https://github.com/PretendoNetwork/website.git
synced 2026-08-28 19:46:35 -05:00
Moved from Trello to GitHub porjects
This commit is contained in:
171
src/cache.js
171
src/cache.js
@@ -1,98 +1,131 @@
|
||||
const Trello = require('trello');
|
||||
const { GraphQLClient, gql } = require('graphql-request');
|
||||
const Stripe = require('stripe');
|
||||
const got = require('got');
|
||||
const config = require('../config.json');
|
||||
|
||||
const trello = new Trello(config.trello.api_key, config.trello.api_token);
|
||||
const graphql = new GraphQLClient('https://api.github.com/graphql', {
|
||||
headers: {
|
||||
Authorization: `bearer ${config.github.graphql_token}`,
|
||||
}
|
||||
});
|
||||
const stripe = new Stripe(config.stripe.secret_key);
|
||||
|
||||
const VALID_LIST_NAMES = ['Not Started', 'Started', 'Completed'];
|
||||
let trelloCache;
|
||||
const getProjectCards = gql`
|
||||
fragment ItemContent on Node {
|
||||
__typename
|
||||
... on DraftIssue {
|
||||
title
|
||||
}
|
||||
... on Issue {
|
||||
title
|
||||
}
|
||||
}
|
||||
|
||||
fragment Itemfields on Node {
|
||||
__typename
|
||||
... on ProjectV2ItemFieldSingleSelectValue {
|
||||
name,
|
||||
field {
|
||||
... on ProjectV2SingleSelectField {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query getProjectCards($orgName: String!) {
|
||||
organization(login: $orgName) {
|
||||
projectsV2(first: 100) {
|
||||
nodes {
|
||||
repositories(first: 1) {
|
||||
nodes {
|
||||
url
|
||||
}
|
||||
}
|
||||
title
|
||||
items(first: 100) {
|
||||
nodes {
|
||||
id
|
||||
content {
|
||||
...ItemContent
|
||||
}
|
||||
fieldValues(first: 20) {
|
||||
nodes {
|
||||
...Itemfields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
let githubProjectsCache;
|
||||
let stripeDonationCache;
|
||||
|
||||
async function getTrelloCache() {
|
||||
const available = await trelloAPIAvailable();
|
||||
if (!available) {
|
||||
return trelloCache || {
|
||||
update_time: 0,
|
||||
sections: [{
|
||||
title: 'Upstream API error',
|
||||
id: '',
|
||||
percentage_complete: '',
|
||||
progress: {
|
||||
not_started: [ 'Trello API unavailable' ],
|
||||
started: [],
|
||||
completed: []
|
||||
}
|
||||
}],
|
||||
};
|
||||
async function getGithubProjectsCache() {
|
||||
if (!githubProjectsCache) {
|
||||
githubProjectsCache = await updateGithubProjectsCache();
|
||||
}
|
||||
|
||||
if (!trelloCache) {
|
||||
trelloCache = await updateTrelloCache();
|
||||
if (githubProjectsCache.update_time < Date.now() - (1000 * 60 * 60)) {
|
||||
githubProjectsCache = await updateGithubProjectsCache();
|
||||
}
|
||||
|
||||
if (trelloCache.update_time < Date.now() - (1000 * 60 * 60)) {
|
||||
trelloCache = await updateTrelloCache();
|
||||
}
|
||||
|
||||
return trelloCache;
|
||||
return githubProjectsCache;
|
||||
}
|
||||
|
||||
async function updateTrelloCache() {
|
||||
const progressCache = {
|
||||
function getProgressField(fields) {
|
||||
const found = fields.nodes.find(v => v.field?.name === 'Status');
|
||||
return found?.name ?? undefined;
|
||||
}
|
||||
|
||||
async function updateGithubProjectsCache() {
|
||||
const projectsCacheData = {
|
||||
update_time: Date.now(),
|
||||
sections: []
|
||||
};
|
||||
|
||||
const boards = await trello.getOrgBoards(config.trello.board_name);
|
||||
const data = await graphql.request(getProjectCards, {
|
||||
orgName: 'PretendoNetwork',
|
||||
});
|
||||
|
||||
for (const board of boards) {
|
||||
const meta = {
|
||||
title: '',
|
||||
id: '',
|
||||
percentage_complete: 0,
|
||||
progress: {
|
||||
not_started: [],
|
||||
started: [],
|
||||
completed: []
|
||||
}
|
||||
};
|
||||
const projects = data.organization.projectsV2.nodes;
|
||||
|
||||
meta.title = board.name;
|
||||
meta.id = board.shortLink;
|
||||
|
||||
const lists = await trello.getListsOnBoard(board.id);
|
||||
|
||||
const listNames = lists.map(list => list.name);
|
||||
const hasAllValidLists = listNames.every(name => VALID_LIST_NAMES.includes(name));
|
||||
|
||||
if (!hasAllValidLists) {
|
||||
for (const project of projects) {
|
||||
if (!project.repositories.nodes[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const cards = await trello.getCardsOnBoard(board.id);
|
||||
|
||||
for (const card of cards) {
|
||||
const cardList = lists.find(({ id }) => id === card.idList);
|
||||
const listName = cardList.name.toLowerCase().replace(' ', '_');
|
||||
|
||||
if (meta.progress[listName]) {
|
||||
meta.progress[listName].push(card.name);
|
||||
const extractedData = {
|
||||
title: project.title,
|
||||
url: project.repositories.nodes[0]?.url,
|
||||
cards: {
|
||||
done: [],
|
||||
in_progress: [],
|
||||
todo: []
|
||||
}
|
||||
};
|
||||
|
||||
for (const { content, fieldValues } of project.items.nodes) {
|
||||
const progress = getProgressField(fieldValues);
|
||||
|
||||
if (!['DraftIssue'].includes(content.__typename)) {
|
||||
continue; // not a supported card, skip
|
||||
}
|
||||
|
||||
if (!progress) {
|
||||
continue; // entry does not have a status, skip
|
||||
}
|
||||
|
||||
extractedData.cards[progress.toLowerCase().replace(' ', '_')]?.push(content.title);
|
||||
}
|
||||
|
||||
if (meta.progress.not_started.length !== 0 || meta.progress.started.length !== 0 || meta.progress.completed.length !== 0) {
|
||||
progressCache.sections.push(meta);
|
||||
}
|
||||
projectsCacheData.sections.push(extractedData);
|
||||
}
|
||||
|
||||
return progressCache;
|
||||
}
|
||||
|
||||
async function trelloAPIAvailable() {
|
||||
const { status } = await got('https://trello.status.atlassian.com/api/v2/status.json').json();
|
||||
return status.indicator !== 'major' && status.indicator !== 'critical';
|
||||
return projectsCacheData;
|
||||
}
|
||||
|
||||
async function getStripeDonationCache() {
|
||||
@@ -147,6 +180,6 @@ async function updateStripeDonationCache() {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getTrelloCache,
|
||||
getGithubProjectsCache,
|
||||
getStripeDonationCache
|
||||
};
|
||||
|
||||
@@ -40,4 +40,4 @@ async function renderDataMiddleware(request, response, next) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = renderDataMiddleware;
|
||||
module.exports = renderDataMiddleware;
|
||||
@@ -1,16 +1,12 @@
|
||||
const { Router } = require('express');
|
||||
const { boards } = require('../../boards/boards.json');
|
||||
const router = new Router();
|
||||
|
||||
const { getTrelloCache } = require('../cache');
|
||||
const { getGithubProjectsCache } = require('../cache');
|
||||
|
||||
router.get('/', async (request, response) => {
|
||||
const renderData = {};
|
||||
|
||||
const renderData = {
|
||||
boards
|
||||
};
|
||||
|
||||
const cache = await getTrelloCache();
|
||||
const githubProjectsCache = await getGithubProjectsCache();
|
||||
|
||||
// Builds the arrays of people for the special thanks section
|
||||
|
||||
@@ -43,37 +39,37 @@ router.get('/', async (request, response) => {
|
||||
percentageSum: 0
|
||||
},
|
||||
percent: 0,
|
||||
progress: {
|
||||
not_started: [],
|
||||
started: [],
|
||||
completed: []
|
||||
cards: {
|
||||
todo: [],
|
||||
in_progress: [],
|
||||
done: []
|
||||
}
|
||||
};
|
||||
|
||||
// Calculates individual completion percentages and progress states
|
||||
cache.sections.forEach(section => {
|
||||
const { not_started, started, completed } = section.progress;
|
||||
githubProjectsCache.sections.forEach(section => {
|
||||
const { todo, in_progress, done } = section.cards;
|
||||
|
||||
// Calculates the completion percentage of the project, and sums it to the total
|
||||
const sectionCompletionPercentage = (completed.length + started.length * 0.5) / (completed.length + started.length + not_started.length);
|
||||
const sectionCompletionPercentage = ((done.length + in_progress.length * 0.5) / (done.length + in_progress.length + todo.length)) || 0;
|
||||
totalProgress._calc.percentageSum += sectionCompletionPercentage;
|
||||
|
||||
const sectionTitle = `${section.title} [${Math.round(sectionCompletionPercentage * 100)}%]`;
|
||||
|
||||
if (completed !== [] && started + not_started === []) {
|
||||
// if all the section tasks have been completed, push to completed
|
||||
totalProgress.progress.completed.push(sectionTitle);
|
||||
} else if (not_started !== [] && started + completed === []) {
|
||||
// if none the section tasks have been completed or started, push to not started
|
||||
totalProgress.progress.not_started.push(sectionTitle);
|
||||
if (done !== [] && in_progress + todo === []) {
|
||||
// if all the section tasks have been done, push to done
|
||||
totalProgress.cards.done.push(sectionTitle);
|
||||
} else if (todo !== [] && in_progress + done === []) {
|
||||
// if none the section tasks have been done or in_progress, push to todo
|
||||
totalProgress.cards.todo.push(sectionTitle);
|
||||
} else {
|
||||
// for all other combos, push to started
|
||||
totalProgress.progress.started.push(sectionTitle);
|
||||
// for all other combos, push to in_progress
|
||||
totalProgress.cards.in_progress.push(sectionTitle);
|
||||
}
|
||||
});
|
||||
|
||||
// Calculates global completion percentage
|
||||
totalProgress.percent = Math.round(totalProgress._calc.percentageSum / cache.sections.length * 100);
|
||||
totalProgress.percent = Math.round(totalProgress._calc.percentageSum / githubProjectsCache.sections.length * 100);
|
||||
|
||||
renderData.featuredFeatureList = totalProgress;
|
||||
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
const { Router } = require('express');
|
||||
const { boards } = require('../../boards/boards.json');
|
||||
const router = new Router();
|
||||
|
||||
const { getTrelloCache, getStripeDonationCache } = require('../cache');
|
||||
const { getGithubProjectsCache, getStripeDonationCache } = require('../cache');
|
||||
|
||||
router.get('/', async (request, response) => {
|
||||
const renderData = {
|
||||
boards
|
||||
progressLists: await getGithubProjectsCache(),
|
||||
donationCache: await getStripeDonationCache()
|
||||
};
|
||||
|
||||
const trelloCache = await getTrelloCache();
|
||||
renderData.progressLists = trelloCache;
|
||||
const stripeDonationCache = await getStripeDonationCache();
|
||||
renderData.donationCache = stripeDonationCache;
|
||||
|
||||
response.render('progress', renderData);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user