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

Previous elections pages #518

Merged
merged 32 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
65cb80c
Previous election page
tomrndom Oct 18, 2023
433b4b7
Change in templates for previous candidates pages
tomrndom Oct 18, 2023
23909e7
Update branch-deploy env vars
tomrndom Oct 18, 2023
faa4553
Add missing env variables to branch deploy context
tomrndom Oct 18, 2023
9a97843
Change context to deploy-preview
tomrndom Oct 18, 2023
31e5838
Change .toml indentation
tomrndom Oct 18, 2023
fcedc2e
Changes in netlify.toml file
tomrndom Oct 18, 2023
7d5ebfc
Pass sponsored project id as string on toml file
tomrndom Oct 18, 2023
fd122b9
Tweaks for real dynmamic pages
smarcet Oct 19, 2023
e4ec266
Merge pull request #519 from OpenStackweb/hotfix/previous-elections-p…
tomrndom Oct 19, 2023
bc2e5f2
Adjusting elections qty to generate pages, add SEO to markdown files
tomrndom Oct 20, 2023
9d8318c
Remove console log on election gold previos page
tomrndom Oct 20, 2023
88957f9
Rollback current election .md files, adjust env variables and cms
tomrndom Oct 20, 2023
9c2fca9
Eletion id field on cms hidden
tomrndom Oct 20, 2023
a5db706
Remove console log
tomrndom Oct 20, 2023
2ce8ab8
Default values for elections variables, add env template
tomrndom Oct 23, 2023
37f1282
Adjust package.json file
tomrndom Oct 24, 2023
195290b
repointed CMS branch
smarcet Oct 24, 2023
c966e12
Fix cms files, add current election data, add redirects
tomrndom Oct 24, 2023
826ce50
Remove redirects from .toml file
tomrndom Oct 24, 2023
022882d
Fix CMS paths for elections
tomrndom Oct 24, 2023
efbe935
trigger deploy
tomrndom Oct 25, 2023
03b8b87
Move redirects from forEach, election template paths function
tomrndom Oct 26, 2023
8d1c94d
Update Election Pages “electionPage”
smarcet Oct 30, 2023
4cc8750
Update Election Pages “electionPage”
iamweswilson Oct 30, 2023
34a876b
Update config.yml
smarcet Oct 31, 2023
a4c3644
Update config.yml
smarcet Oct 31, 2023
53d50ec
Update Election Pages “electionGoldCandidatesPage”
iamweswilson Oct 31, 2023
32c2487
Update Election Pages “electionCandidatesPage”
iamweswilson Oct 31, 2023
3e01109
Update Election Pages “electionPage”
iamweswilson Oct 31, 2023
4c6adb5
Update Election Pages “electionPage”
iamweswilson Oct 31, 2023
94d349d
Update config.yml
smarcet Nov 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 289 additions & 4 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ const axios = require('axios')
const {createFilePath} = require('gatsby-source-filesystem')
const {fmImagesToRelative} = require('gatsby-remark-relative-images')
const {ClientCredentials} = require('simple-oauth2');
const yaml = require("yaml")
const moment = require("moment-timezone");
const prevElectionsBasePath = 'src/pages/election/previous-elections';
const electionsSinceYear = 2023;
tomrndom marked this conversation as resolved.
Show resolved Hide resolved
const currentYear = new Date().getFullYear();
const minimunElectionsToShow = 2;
tomrndom marked this conversation as resolved.
Show resolved Hide resolved

const electionsToShow = (currentYear - electionsSinceYear) + minimunElectionsToShow;

const myEnv = require("dotenv").config({
path: `.env`,
Expand Down Expand Up @@ -107,6 +115,55 @@ const SSR_getSponsoredProjects = async (baseUrl) => {
.catch(e => console.log('ERROR: ', e));
}

const SSR_getPreviousElections = async (baseUrl, accessToken, page = 1) => {
const currentDate = parseInt(Date.now()/1000);
// minimun per page is 5
const perPage = electionsToShow > 5 ? electionsToShow : 5;
return await axios.get(
`${baseUrl}/api/v1/elections/`,
{
params: {
access_token: accessToken,
page: page,
per_page: perPage,
filter: `closes<${currentDate}`,
order: '-closes'
}
}).then((response) => response.data)
.catch(e => console.log('ERROR: ', e));
};

const SSR_getPreviousElectionCandidates = async (baseUrl, accessToken, electionId, page = 1) => {
return await axios.get(
`${baseUrl}/api/v1/elections/${electionId}/candidates/`,
{
params: {
access_token: accessToken,
per_page: 100,
page: page,
order: '+first_name,+last_name',
expand: 'member, member.election_applications, member.election_applications.nominator',
fields: 'member.election_applications.nominator.first_name, member.election_applications.nominator.last_name'
}
}).then((response) => response.data)
.catch(e => console.log('ERROR: ', e));
};

const SSR_getPreviousElectionGoldCandidates = async (baseUrl, accessToken, electionId, page = 1) => {
return await axios.get(
`${baseUrl}/api/v1/elections/${electionId}/candidates/gold`,
{
params: {
access_token: accessToken,
per_page: 100,
page: page,
order: '+first_name,+last_name',
expand: 'member',
}
}).then((response) => response.data)
.catch(e => console.log('ERROR: ', e));
};

exports.onPreBootstrap = async () => {
const apiBaseUrl = process.env.GATSBY_API_BASE_URL;
const buildScopes = process.env.GATSBY_BUILD_SCOPES;
Expand Down Expand Up @@ -169,9 +226,166 @@ exports.onPreBootstrap = async () => {
const sponsoredProjects = await SSR_getSponsoredProjects(apiBaseUrl);
if (sponsoredProjects) {
writeToJson('src/content/sponsored-projects.json', sponsoredProjects);
}
}
}

exports.sourceNodes = async ({ actions, createNodeId, createContentDigest }) => {
const { createNode } = actions;

const apiBaseUrl = process.env.GATSBY_API_BASE_URL;
const buildScopes = process.env.GATSBY_BUILD_SCOPES;

console.log(`onSourceNodes...`);

const config = {
client: {
id: process.env.GATSBY_OAUTH2_CLIENT_ID_BUILD,
secret: process.env.GATSBY_OAUTH2_CLIENT_SECRET_BUILD
},
auth: {
tokenHost: process.env.GATSBY_IDP_BASE_URL,
tokenPath: process.env.GATSBY_OAUTH_TOKEN_PATH
},
options: {
authorizationMethod: 'header'
}
};

const accessToken = await getAccessToken(config, buildScopes).then(({token}) => token.access_token).catch(e => console.log('Access Token error', e));

// data for previous electionsfilePath
const previousElections = await SSR_getPreviousElections(apiBaseUrl, accessToken)
console.log('check previous election...', previousElections)
const lastElections = previousElections.data.slice(0, electionsToShow);
if (lastElections && lastElections.length > 0) {
let candidates = [];
let goldCandidates = [];
// create paths
fs.mkdirSync(prevElectionsBasePath, { recursive: true } );
fs.mkdirSync(`${prevElectionsBasePath}/candidates`, { recursive: true } );
fs.mkdirSync(`${prevElectionsBasePath}/candidates/gold`, { recursive: true } );

for (const election of lastElections) {

function formatMarkdown(post) {
const { body } = post
delete post.body
return
}

const seoObject = {
image: "/img/OpenInfra-icon-white.jpg",
twitterUsername: "@OpenInfraDev"
}

const electionYear = moment(election.closes * 1000).utc().format('YYYY');
// create MD file using yaml ...
if(!fs.existsSync(`${prevElectionsBasePath}/${election.id}.md`))
fs.writeFileSync(`${prevElectionsBasePath}/${election.id}.md`, `---\n${yaml.stringify({
templateKey: 'election-page-previous',
electionYear:electionYear,
electionId:election.id,
title:election.name,
seo: {
...seoObject,
title: election.name,
url: `https://openinfra.dev/election/${electionYear}-individual-director-election`,
description: `Individual Member Director elections for the ${electionYear} Board of Directors`
}
})}---\n`, 'utf8', function (err) {
if (err) {
console.log(err);
}
});

// create MD file using yaml ...
if(!fs.existsSync(`${prevElectionsBasePath}/candidates/${election.id}_candidates.md`))
fs.writeFileSync(`${prevElectionsBasePath}/candidates/${election.id}_candidates.md`, `---\n${yaml.stringify({
templateKey: 'election-candidates-page-previous',
electionYear:electionYear,
electionId:election.id,
title:election.name + ' Candidates',
seo: {
...seoObject,
title: election.name,
url: `https://openinfra.dev/election/${electionYear}-individual-director-election/candidates`,
description: `Individual Member Director elections for the ${electionYear} Board of Directors`
}})}---\n`, 'utf8', function (err) {
if (err) {
console.log(err);
}
});

if(!fs.existsSync(`${prevElectionsBasePath}/candidates/gold/${election.id}_gold_candidates.md`))
fs.writeFileSync(`${prevElectionsBasePath}/candidates/gold/${election.id}_gold_candidates.md`, `---\n${yaml.stringify({
templateKey: 'election-gold-candidates-page-previous',
electionYear:electionYear,
electionId:election.id,
title:election.name + ' Gold Candidates',
tomrndom marked this conversation as resolved.
Show resolved Hide resolved
seo: {
...seoObject,
title: election.name,
url: `https://openinfra.dev/election/${electionYear}-individual-director-election/candidates/gold`,
description: `Individual Member Director elections for the ${electionYear} Board of Directors`
}})}---\n`, 'utf8', function (err) {
if (err) {
console.log(err);
}
});

const electionCandidates = await SSR_getPreviousElectionCandidates(apiBaseUrl, accessToken, election.id);
const electionGoldCandidates = await SSR_getPreviousElectionGoldCandidates(apiBaseUrl, accessToken, election.id);

if (Array.isArray(electionCandidates.data) && electionCandidates.data.length > 0) candidates = [...candidates, ...electionCandidates.data];
if (Array.isArray(electionGoldCandidates.data) && electionGoldCandidates.data.length > 0) goldCandidates = [...goldCandidates, ...electionGoldCandidates.data];
}

// ingest api data on graphql ...

lastElections.forEach(election => {
createNode({
...election,
id: `${election.id}`,
parent: null,
children: [],
internal: {
type: 'ElectionData', // Replace with an appropriate type
contentDigest: createContentDigest(election),
},
});
})

candidates.forEach(candidate => {
createNode({
...candidate,
id: createNodeId(`CandidateData-${candidate.member.id}`),
election_id: `${candidate.election_id}`,
parent: null,
children: [],
internal: {
type: 'CandidateData', // Replace with an appropriate type
contentDigest: createContentDigest(candidate),
},
});
})

goldCandidates.forEach(candidate => {
createNode({
...candidate,
id: createNodeId(`GoldCandidateData-${candidate.member.id}`),
election_id: `${candidate.election_id}`,
parent: null,
children: [],
internal: {
type: 'GoldCandidateData', // Replace with an appropriate type
contentDigest: createContentDigest(candidate),
},
});
})
}

};

// explicit Frontmatter declaration to make category, author and date, optionals.
exports.createSchemaCustomization = ({actions}) => {
const {createTypes} = actions
Expand Down Expand Up @@ -239,16 +453,83 @@ exports.createSchemaCustomization = ({actions}) => {
col1: String
col2: Date @dateformat
}
type ElectionData implements Node {
opens: Int
closes: Int
nominationOpens: Int
nominationCloses: Int
nominationApplicationDeadline: Int
}
`
createTypes(typeDefs)
}

exports.createPages = ({actions, graphql}) => {
exports.createPages = async ({actions, graphql}) => {
tomrndom marked this conversation as resolved.
Show resolved Hide resolved
const {createPage} = actions

await graphql(`
tomrndom marked this conversation as resolved.
Show resolved Hide resolved
{
allMarkdownRemark(
limit: 1000
filter: {frontmatter: {templateKey: {in: ["election-page-previous", "election-candidates-page-previous", "election-gold-candidates-page-previous"]}}}
) {
edges {
node {
id
fields {
slug
}
frontmatter {
title
templateKey
electionId
electionYear
}
}
}
}
}
`).then(result => {

console.log(`createPage res ${JSON.stringify(result)}`);

if (result.errors) {
result.errors.forEach(e => console.error(e.toString()))
return Promise.reject(result.errors)
}

const electionsPages = result.data.allMarkdownRemark.edges;

electionsPages.forEach(edge => {

const id = edge.node.id;
const electionId = edge.node.frontmatter.electionId.toString();
const electionYear = edge.node.frontmatter.electionYear;
const electionPath = edge.node.frontmatter.templateKey === 'election-page-previous' ?
`/election/${electionYear}-individual-director-election`:
edge.node.frontmatter.templateKey === 'election-candidates-page-previous' ?
`/election/${electionYear}-individual-director-election/candidates`:
`/election/${electionYear}-individual-director-election/candidates/gold`;
console.log(`createPage processing edge ${JSON.stringify(edge)} path ${electionPath}`);
createPage({
path: electionPath,
component: path.resolve(
`src/templates/${String(edge.node.frontmatter.templateKey)}.js`
),
// additional data can be passed via context
context: {
id,
electionId
},
})

})

});

return graphql(`
{
allMarkdownRemark(limit: 1000) {
allMarkdownRemark(limit: 1000, filter: {frontmatter: {electionId: {eq: null}}}) {
edges {
node {
id
Expand All @@ -262,6 +543,7 @@ exports.createPages = ({actions, graphql}) => {
title
author
templateKey
electionId
seo {
url
}
Expand All @@ -277,12 +559,13 @@ exports.createPages = ({actions, graphql}) => {
return Promise.reject(result.errors)
}

const pages = result.data.allMarkdownRemark.edges
const pages = result.data.allMarkdownRemark.edges;

pages.forEach(edge => {
if (edge.node.frontmatter.templateKey) {
const id = edge.node.id
const SEO = edge.node.frontmatter.seo ? edge.node.frontmatter.seo : null;
const electionId = edge.node.frontmatter.electionId ? `${edge.node.frontmatter.electionId}` : null
tomrndom marked this conversation as resolved.
Show resolved Hide resolved
const slug = SEO && SEO.url ? SEO.url.replace('https://osf.dev', '').replace('https://openinfra.dev', '') : edge.node.fields.slug;
createPage({
path: slug,
Expand All @@ -293,6 +576,7 @@ exports.createPages = ({actions, graphql}) => {
// additional data can be passed via context
context: {
id,
electionId
tomrndom marked this conversation as resolved.
Show resolved Hide resolved
},
})
}
Expand Down Expand Up @@ -359,6 +643,7 @@ exports.onCreateNode = ({node, actions, getNode}) => {
}
}


exports.onCreateWebpackConfig = ({actions, plugins, loaders}) => {
actions.setWebpackConfig({
resolve: {
Expand Down
Loading