Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 32 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import express from 'express'
import path from 'path'
import {fileURLToPath} from 'node:url'

//import of routes
import getCustomObjects from "./routes/getCustomObjects.js"
import updateCustomObjects from "./routes/updateCustomObjects.js"

//instantiation of the express application
const app = express()

//setup of __dirname because its not natively available ES6
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

//serving of static files such as the style.css file
app.use(express.static(path.join(__dirname, 'public')))

//setup of the view engine

app.set("views", path.join(__dirname, 'views'))
app.set("view engine", "pug")
// Parse application/x-www-form-urlencoded form data
app.use(express.urlencoded({ extended: true }));

// Enable json parsing
app.use(express.json());
//registration of routes
app.use("/", getCustomObjects)
app.use("/", updateCustomObjects)

export default app
8 changes: 8 additions & 0 deletions bin/www.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//import of the express application instance
import app from "../app.js"

//id of the port to listen on
const port = process.env.PORT || 3000

//local host to listen on
app.listen(port, () => console.log(`Listening on port ${port}`))
38 changes: 38 additions & 0 deletions controllers/getCustomObjects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import axios from "axios";

/**
* Controller function to get existing records of a custom object from the HubSpot API and render
* to data via a Pug template to the user
* @param req
* @param res
* @returns {Promise<void>}
*/
export const getCustomObjects = async (req, res) => {

// Setup of axios request
const objectTypeId = 'p145883771_plants';
const properties = 'plant_name,species,plant_size';
const getCustomObjectEndpoint = `https://api.hubapi.com/crm/v3/objects/${objectTypeId}?properties=${properties}`;
const axiosConfig = {
method: 'get',
url: getCustomObjectEndpoint,
headers: {
Authorization: `Bearer ${process.env.PRIVATE_APP_TOKEN}`,
'Content-Type': 'application/json',
}
}
// Axios get request to the specified API to get and render the information in a Pug template.
// Use of a try/catch block in case the axios call fails
try {

const response = await axios(axiosConfig);
const data = response.data.results;
res.render('customObjects', { title: 'Custom Object | Plants', data });

} catch (error) {

console.error(error);

}

}
56 changes: 56 additions & 0 deletions controllers/updateCustomObjects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import axios from "axios";

/**
* Controller function to render a custom form when a get call is made to route '/update-cobj'
* @param req
* @param res
* @returns {Promise<void>}
*/
export const getFormData = async (req, res) => {
res.render('updates', {title: 'Update Custom Object Form | Integrating With HubSpot I Practicum'});
}

/**
* Controller to make a post request to the HubSpot API to add new records to a custom object
* @param req
* @param res
* @returns {Promise<void>}
*/
export const updateCustomObject = async (req, res) => {

// The submitted details from the custom form in the updates.pug file received via the req.body as a POST method form
const {plant_name, plant_size, species} = req.body

// Setup of the axios request
const objectTypeId = 'p145883771_plants'
const updateCustomObjectsEndpoint = `https://api.hubapi.com/crm/v3/objects/${objectTypeId}`;
const newData = {
properties: {
"plant_name": plant_name,
"plant_size": plant_size,
"species": species,
}
}
const axiosConfig = {
method: 'post',
data: newData,
url: updateCustomObjectsEndpoint,
headers: {
Authorization: `Bearer ${process.env.PRIVATE_APP_TOKEN}`,
'Content-Type': 'application/json',
}
}
// The try/catch block for the axios request in case it fails and a redirect back to the home page if successful
try {

await axios(axiosConfig);
res.redirect('/');

} catch (error) {

console.error(error);

}


}
86 changes: 43 additions & 43 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,49 +22,49 @@ const PRIVATE_APP_ACCESS = '';

// * Code for Route 3 goes here

/**
* * This is sample code to give you a reference for how you should structure your calls.

* * App.get sample
app.get('/contacts', async (req, res) => {
const contacts = 'https://api.hubspot.com/crm/v3/objects/contacts';
const headers = {
Authorization: `Bearer ${PRIVATE_APP_ACCESS}`,
'Content-Type': 'application/json'
}
try {
const resp = await axios.get(contacts, { headers });
const data = resp.data.results;
res.render('contacts', { title: 'Contacts | HubSpot APIs', data });
} catch (error) {
console.error(error);
}
});

* * App.post sample
app.post('/update', async (req, res) => {
const update = {
properties: {
"favorite_book": req.body.newVal
}
}

const email = req.query.email;
const updateContact = `https://api.hubapi.com/crm/v3/objects/contacts/${email}?idProperty=email`;
const headers = {
Authorization: `Bearer ${PRIVATE_APP_ACCESS}`,
'Content-Type': 'application/json'
};

try {
await axios.patch(updateContact, update, { headers } );
res.redirect('back');
} catch(err) {
console.error(err);
}

});
*/
/**
* * This is sample code to give you a reference for how you should structure your calls.

* * App.get sample
app.get('/contacts', async (req, res) => {
const contacts = 'https://api.hubspot.com/crm/v3/objects/contacts';
const headers = {
Authorization: `Bearer ${PRIVATE_APP_ACCESS}`,
'Content-Type': 'application/json'
}
try {
const resp = await axios.get(contacts, { headers });
const data = resp.data.results;
res.render('contacts', { title: 'Contacts | HubSpot APIs', data });
} catch (error) {
console.error(error);
}
});

* * App.post sample
app.post('/update', async (req, res) => {
const update = {
properties: {
"favorite_book": req.body.newVal
}
}

const email = req.query.email;
const updateContact = `https://api.hubapi.com/crm/v3/objects/contacts/${email}?idProperty=email`;
const headers = {
Authorization: `Bearer ${PRIVATE_APP_ACCESS}`,
'Content-Type': 'application/json'
};

try {
await axios.patch(updateContact, update, { headers } );
res.redirect('back');
} catch(err) {
console.error(err);
}

});
*/


// * Localhost
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon -r dotenv/config bin/www.js"
},
"author": "HubSpot Academy learner",
"license": "ISC",
"dependencies": {
"axios": "^1.3.5",
"dotenv": "^16.4.7",
"express": "^4.18.2",
"nodemon": "^3.1.9",
"pug": "^3.0.2"
}
}
14 changes: 14 additions & 0 deletions public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,18 @@ input[type="submit"] {
border: none;
padding: .375rem 1rem;
margin-top: 10px;
}

.custom-plants{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: green;
}

.custom-plants__table__heading,
.custom-plants__table__cell{
padding: 10px 40px;
}
12 changes: 12 additions & 0 deletions routes/getCustomObjects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import express from 'express'

//import of the controller function for this route
import {getCustomObjects} from "../controllers/getCustomObjects.js"

//instantiation of the router object
const router = express.Router()

//get route to obtain custom object data from the HubSpot account
router.get('/', getCustomObjects)

export default router
15 changes: 15 additions & 0 deletions routes/updateCustomObjects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import express from 'express'

//import of controller functions for the two routes
import {getFormData, updateCustomObject} from "../controllers/updateCustomObjects.js"

//instantiation of the router object
const router = express.Router()

//the get route to get and display the custom form to add records to the custom object
router.get("/update-cobj", getFormData)

//the post route to make use of the information submitted through the form and add a record to the custom object via the appropriate hubspot api endpoint
router.post("/update-cobj", updateCustomObject)

export default router
15 changes: 0 additions & 15 deletions views/contacts.pug

This file was deleted.

27 changes: 27 additions & 0 deletions views/customObjects.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
doctype html
html
head
// Interpolation of title
title= `${title}`
meta(name="viewport" content="width=device-width, initial-scale=1")
link(rel="stylesheet", href="/css/style.css")
body
.custom-plants
h1.custom-plants__heading Custom Object
h2.custom-plants__subheading Plants
// Link to the /object-cobj get route
a.custom-plants__update-link(href='./update-cobj') Add to this table
// Setup of the table needed to render the data
table.custom-plants__table
tr.custom-plants__table__header-row
th.custom-plants__table__heading Name
th.custom-plants__table__heading Species
th.custom-plants__table__heading Size
// Loop through the data received from the get route that contains individual records of the
// custom object
each customPlants in data
tr.custom-plants__table__row
// Interpolation of the specific data points into a table
td.custom-plants__table__cell #{customPlants.properties.plant_name}
td.custom-plants__table__cell #{customPlants.properties.species}
td.custom-plants__table__cell #{customPlants.properties.plant_size}
28 changes: 28 additions & 0 deletions views/updates.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
doctype html
html
head
// Interpolation of the title received from the get route associated with this template
title= `${title}`
meta(name="viewport" content="width=device-width, initial-scale=1")
link(rel="stylesheet", href="/css/style.css")
body
.form-wrapper
// Interpolation of the title
h1.updates__heading #{title}
// Link back to the homepage
a.updates__homepage-link(href="/") Homepage
// Setup of the form with a POST method for submitting data to the HubSpot API for addition to the
// custom object
form.updates__form(action="/update-cobj" method="POST")
.updates__form-control
label(for="plant-name") Plant Name
input(type="text" name="plant_name" id="plant-name")
.updates__form-control
label(for="plant-size") Plant Size
input(type="text" name="plant_size" id="plant-size")
.updates__form-control
label(for="plant-species") Plant Species
input(type="text" name="species" id="plant-species")
// Submit button to trigger submission of data to the /update-cobj post route
.updates__form-control-btn
input(type="submit" value="Submit")