From ecd04230591049866d94457d5781df5bc33c3789 Mon Sep 17 00:00:00 2001 From: kaxada Date: Thu, 4 Apr 2024 17:54:19 -0500 Subject: [PATCH 1/2] added client package for dev envs Signed-off-by: kaxada --- package-lock.json | 35 ++++++++++++++++++++++++++++++++++- package.json | 3 ++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7dcc8e..3388406 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,8 @@ "husky": "^8.0.3", "jsonlint": "^1.6.3", "lint-staged": "^13.2.3", - "prettier": "^2.8.8" + "prettier": "^2.8.8", + "smee-client": "^2.0.1" } }, "node_modules/@babel/runtime": { @@ -2260,6 +2261,15 @@ "node": ">= 0.6" } }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/execa": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", @@ -5300,6 +5310,29 @@ "npm": ">= 3.0.0" } }, + "node_modules/smee-client": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/smee-client/-/smee-client-2.0.1.tgz", + "integrity": "sha512-s2+eG9vNMWQQvu8Jz+SfAiihpYsmaMtcyPnHtBuZEhaAAQOQV63xSSL9StWv2p08xKgvSC8pEZ28rXoy41FhLg==", + "dev": true, + "dependencies": { + "commander": "^12.0.0", + "eventsource": "^2.0.2", + "validator": "^13.11.0" + }, + "bin": { + "smee": "bin/smee.js" + } + }, + "node_modules/smee-client/node_modules/commander": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", diff --git a/package.json b/package.json index 2b410b2..7bf5878 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "husky": "^8.0.3", "jsonlint": "^1.6.3", "lint-staged": "^13.2.3", - "prettier": "^2.8.8" + "prettier": "^2.8.8", + "smee-client": "^2.0.1" } } From 0c90a29ff509286944eff030529afdacbf8fb4c1 Mon Sep 17 00:00:00 2001 From: kaxada Date: Thu, 4 Apr 2024 21:50:22 -0500 Subject: [PATCH 2/2] added events table and API routes Signed-off-by: kaxada --- .github/ISSUE_TEMPLATE/bug_report.md | 24 ++++---- .github/ISSUE_TEMPLATE/feature_request.md | 7 +-- CONTRIBUTING.md | 50 +++++++++-------- database/controllers/event.controller.js | 49 ++++++++++++++++ database/models/event.model.js | 59 ++++++++++++++++++++ event_badging/index.js | 2 + event_badging/logic/calculate.badge.js | 3 +- event_badging/logic/index.js | 2 + event_badging/logic/saveEvent.js | 68 +++++++++++++++++++++++ event_badging/logic/updateReadme.js | 2 +- index.js | 3 +- providers/github/auth.js | 4 +- routes/index.js | 12 ++-- 13 files changed, 238 insertions(+), 47 deletions(-) create mode 100644 database/controllers/event.controller.js create mode 100644 database/models/event.model.js create mode 100644 event_badging/logic/saveEvent.js diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..9b77ea7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..2bc5d5f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,10 +1,9 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- **Is your feature request related to a problem? Please describe.** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46e0f53..66636dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,7 +36,7 @@ Configure MySQL and make sure it is running on your machine before you proceed w 1. You'll need to [create a GitHub OAuth App](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) on your personal GitHub account. Creating a GitHub OAuth App will automatically generate a `Client_ID` and will also enable you to generate a `Client_Secret` for your OAuth App. Store these values safely because they will be needed while generating a `.env` file for the first time. -2. Create your personal [Augur Application](https://projectbadge.chaoss.io/account/settings?section=application) in order to generate an 'augur_client_secret'. Following the link, you will click on "register" and then fill in a couple of fields as required which will set up an account which you will log into. Click on your username(the one you filled in for the "user ID") at the top left and select "profile" which will take you to account settings. Under the account settings, in the left sidebar, click on "applications" and create a new application by entering an App name and a Redirect URL which will generate the `augur_client_secret` which will be listed in the last column of **_Your Apps_** table. Store the `augur_client_secret` together with the above GitHub OAuth credentials since it will be needed too while generating a `.env` file for the first time. The `augur_client_secret` which is the `AUGUR_CLIENT_SECRET` key is used to connect to the Augur API to submit repositories to the Augur Library for further badging. +2. Create your personal [Augur Application](https://projectbadge.chaoss.io/account/settings?section=application) in order to generate an 'augur*client_secret'. Following the link, you will click on "register" and then fill in a couple of fields as required which will set up an account which you will log into. Click on your username(the one you filled in for the "user ID") at the top left and select "profile" which will take you to account settings. Under the account settings, in the left sidebar, click on "applications" and create a new application by entering an App name and a Redirect URL which will generate the `augur_client_secret` which will be listed in the last column of \*\*\_Your Apps*\*\* table. Store the `augur_client_secret` together with the above GitHub OAuth credentials since it will be needed too while generating a `.env` file for the first time. The `augur_client_secret` which is the `AUGUR_CLIENT_SECRET` key is used to connect to the Augur API to submit repositories to the Augur Library for further badging. After generating those values, @@ -57,7 +57,7 @@ After generating those values, npm install # installs packages and dependencies ``` -2. **Make sure project is running**: This starts a *.env* configuration process if the *.env* file is missing. +2. **Make sure project is running**: This starts a _.env_ configuration process if the _.env_ file is missing. ```bash npm run dev # this command will trigger a series of configuration questions in order setup your environmental variables @@ -98,39 +98,43 @@ BadgingAPI follows a specific code style and coding standards. Please make sure - **Variables and functions**: camelCase - ````markdown - myVariable = 10; - - function exampleFunction() { - return "Hello, World!" - }; + ```markdown + myVariable = 10; + + function exampleFunction() { + return "Hello, World!" + }; + ``` - **Classes and constructors**: PascalCase - ````markdown - class MyClass { - constructor(value) { - this.value = value; - } - }; + ```markdown + class MyClass { + constructor(value) { + this.value = value; + } + }; + ``` - **Filenames, constants, and environment variables**: Snake_case - ````markdown - my_file_name.txt + ```markdown + my_file_name.txt - const MAX_ATTEMPTS = 5; + const MAX_ATTEMPTS = 5; - DATABASE_URL = "localhost:3000" + DATABASE_URL = "localhost:3000" + ``` - **HTML attributes and CSS class names**: Kebab-case - ````markdown -
+ ```markdown +
- .my-element { - color: red; - }; + .my-element { + color: red; + }; + ``` ### Issue Tracking diff --git a/database/controllers/event.controller.js b/database/controllers/event.controller.js new file mode 100644 index 0000000..a8ef91a --- /dev/null +++ b/database/controllers/event.controller.js @@ -0,0 +1,49 @@ +const Event = require("../models/event.model"); + +const createEvent = async (event) => { + try { + const { event_name, event_URL, badge, reviewers, application } = event; + + const newEvent = await Event.create({ + event_name, + event_URL, + badge, + reviewers, + application, + }); + + console.log(`Event ${newEvent.event_name} created successfully`); + } catch (error) { + console.error(error); + } +}; + +// Get all Events +const getAllEvents = async (req, res) => { + try { + const events = await Event.findAll(); + res.status(200).json(events); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; + +// Get event by ID +const getEventById = async (req, res) => { + const { id } = req.params; + try { + const event = await Event.findByPk(id); + if (!event) { + return res.status(404).json({ message: "Event not found" }); + } + res.status(200).json(event); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; + +module.exports = { + createEvent, + getAllEvents, + getEventById, +}; diff --git a/database/models/event.model.js b/database/models/event.model.js new file mode 100644 index 0000000..acc114d --- /dev/null +++ b/database/models/event.model.js @@ -0,0 +1,59 @@ +const { DataTypes } = require("sequelize"); +const sequelize = require("../helpers/sequelize"); + +const Event = sequelize.define("events", { + date: { + type: DataTypes.DATE, + defaultValue: DataTypes.NOW, + allowNull: false, + }, + event_name: { + type: DataTypes.STRING, + allowNull: false, + }, + event_URL: { + type: DataTypes.STRING, + allowNull: false, + }, + badge: { + type: DataTypes.JSON, + allowNull: false, + }, + reviewers: { + type: DataTypes.JSON, + allowNull: false, + validate: { + isValidReviewers(value) { + if (!Array.isArray(value)) { + throw new Error("Reviewers must be an array."); + } + for (const reviewer of value) { + if (typeof reviewer.name !== "string" || reviewer.name.length > 255) { + throw new Error( + "Reviewer name must be a string with max length 255." + ); + } + if (!isValidURL(reviewer.github_profile_link)) { + throw new Error("Invalid GitHub profile link format."); + } + } + }, + }, + }, + application: { + type: DataTypes.JSON, + allowNull: false, + }, +}); + +// Helper function to validate URL format +function isValidURL(url) { + try { + new URL(url); + return true; + } catch (error) { + return false; + } +} + +module.exports = Event; diff --git a/event_badging/index.js b/event_badging/index.js index f883083..5ff0de7 100644 --- a/event_badging/index.js +++ b/event_badging/index.js @@ -5,6 +5,7 @@ const { endReview, assignChecklist, updateReadme, + saveEvent, } = require("./logic/index.js"); const eventBadging = async (name, octokit, payload) => { @@ -35,6 +36,7 @@ const eventBadging = async (name, octokit, payload) => { // when issue is closed, update the readme with the event if (name === "issues" && payload.action === "closed") { + saveEvent(octokit, payload); updateReadme(octokit, payload); } } else if ( diff --git a/event_badging/logic/calculate.badge.js b/event_badging/logic/calculate.badge.js index 2b2648e..eaa8b1f 100644 --- a/event_badging/logic/calculate.badge.js +++ b/event_badging/logic/calculate.badge.js @@ -89,7 +89,8 @@ const calculateBadge = async (octokit, payload) => { htmlBadgeImage: htmlBadgeImage, reviewResult: reviewResult, reviewerCount: reviewerCount, - assignedBadge: badgeAssigned[0], + assigned_badge: badgeAssigned[0], + badge_URL: url, }; return messageObj; diff --git a/event_badging/logic/index.js b/event_badging/logic/index.js index 47e0abd..3def391 100644 --- a/event_badging/logic/index.js +++ b/event_badging/logic/index.js @@ -4,6 +4,7 @@ const help = require("./help"); const welcome = require("./welcome"); const assignChecklist = require("./assignChecklist"); const updateReadme = require("./updateReadme"); +const saveEvent = require("./saveEvent"); module.exports = { welcome, @@ -11,5 +12,6 @@ module.exports = { getResults, endReview, assignChecklist, + saveEvent, updateReadme, }; diff --git a/event_badging/logic/saveEvent.js b/event_badging/logic/saveEvent.js new file mode 100644 index 0000000..03b3cb1 --- /dev/null +++ b/event_badging/logic/saveEvent.js @@ -0,0 +1,68 @@ +const { createEvent } = require("../../database/controllers/event.controller"); +const calculateBadge = require("./calculate.badge.js"); + +const saveEvent = async (octokit, payload) => { + let { assigned_badge, badge_URL } = await calculateBadge(octokit, payload); // get badge name + + const event_name = payload.issue.title.replace(/\[(.*?)\] /gi, ""); + let event_URL; + if (payload.issue.title.includes("[Virtual Event]")) { + event_URL = await payload.issue.body + .slice( + payload.issue.body.indexOf("- Link to the Event Website: "), + payload.issue.body.indexOf( + "- Provide verification that you are an event organizer: " + ) - 2 + ) + .replace("- Link to the Event Website: ", ""); + } + + if (payload.issue.title.includes("[In-Person Event]")) { + event_URL = await payload.issue.body + .slice( + payload.issue.body.indexOf("- Link to the Event Website: "), + payload.issue.body.indexOf("- Are you an organizer ") - 2 + ) + .replace("- Link to the Event Website: ", ""); + } + // get badge name + const badge = { + name: assigned_badge, + badgeURL: badge_URL, + }; + + // get array of assignees + const reviewers = await payload.issue.assignees.map((assignee) => { + return { + name: assignee.login, + github_profile_link: assignee.html_url, + }; + }); + + const application = { + app_no: payload.issue.number, + app_URL: payload.issue.html_url, + }; + + try { + const newEvent = { + event_name, + event_URL, + badge, + reviewers, + application, + }; + + const event = await createEvent(newEvent); + if (event) { + return event; + } else { + return ""; + } + } catch (error) { + console.error(error); + return ""; + } +}; + +module.exports = saveEvent; diff --git a/event_badging/logic/updateReadme.js b/event_badging/logic/updateReadme.js index 53cc444..6b07f41 100644 --- a/event_badging/logic/updateReadme.js +++ b/event_badging/logic/updateReadme.js @@ -42,7 +42,7 @@ const updateReadme = async (octokit, payload) => { const event = `[${eventName}](${eventLink})`; // get badge name - const badge = `![${resultsObj.assignedBadge}]`; + const badge = `![${resultsObj.assigned_badge}]`; // get array of assignees const reviewers = await payload.issue.assignees.map((assignee) => { diff --git a/index.js b/index.js index c4803e1..b5121d3 100644 --- a/index.js +++ b/index.js @@ -42,9 +42,8 @@ routes.setupRoutes(app); * The smee.io service is started using the smee.start() method. * */ +const SmeeClient = require("smee-client"); if (process.env.NODE_ENV === "development") { - const SmeeClient = require("smee-client"); - const smee = new SmeeClient({ source: `${process.env.SMEECLIENT_URL}`, target: `http://localhost:${process.env.PORT}/api/event_badging`, diff --git a/providers/github/auth.js b/providers/github/auth.js index a02d3ed..cbed8d4 100644 --- a/providers/github/auth.js +++ b/providers/github/auth.js @@ -82,7 +82,9 @@ const handleOAuthCallback = async (req, res) => { const octokit = new Octokit({ auth: `${accessToken}` }); // Authenticated user details - const { user_info: userInfo, errors: userInfoErrors } = await getUserInfo(octokit); + const { user_info: userInfo, errors: userInfoErrors } = await getUserInfo( + octokit + ); if (userInfoErrors.length > 0) { res.status(500).send(userInfoErrors.join()); return; diff --git a/routes/index.js b/routes/index.js index f6770e5..b355fb1 100644 --- a/routes/index.js +++ b/routes/index.js @@ -3,6 +3,7 @@ const Repo = require("../database/models/repo.model.js"); const eventBadging = require("../event_badging/index.js"); const github_helpers = require("../providers/github/APICalls.js"); const gitlab_helpers = require("../providers/gitlab/APICalls.js"); +const { getAllEvents } = require("../database/controllers/event.controller.js"); const { githubAuth, githubAuthCallback, @@ -159,10 +160,6 @@ const setupRoutes = (app) => { app.get("/api/badgedRepos", badgedRepos); app.post("/api/repos-to-badge", reposToBadge); - app.get("*", (req, res) => { - res.status(404).send("Endpoint not found or unresponsive"); - }); - // github app routes app.post("/api/event_badging", async (req, res) => { const { @@ -176,6 +173,13 @@ const setupRoutes = (app) => { console.info(`Received ${name} event from Github`); res.send("ok"); }); + + // route to get all events + app.get("/api/badged_events", getAllEvents); + + app.get("*", (req, res) => { + res.status(404).send("Endpoint not found or unresponsive"); + }); }; module.exports = {