inital commit
This commit is contained in:
commit
df880c2f4c
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.env
|
||||
node_modules
|
304
index.js
Normal file
304
index.js
Normal file
@ -0,0 +1,304 @@
|
||||
// index.js
|
||||
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const axios = require('axios');
|
||||
const sgMail = require('@sendgrid/mail');
|
||||
const WorkTicketVisitModel = require('./models/workticketvisit');
|
||||
const WorkTicketModel = require("./models/workticket");
|
||||
const ContactModel = require("./models/contact");
|
||||
const OpportunityModel = require('./models/opportunity');
|
||||
const PropertyModel = require('./models/property');
|
||||
const PropertyContactModel = require('./models/propertyContact');
|
||||
|
||||
|
||||
require('dotenv').config();
|
||||
|
||||
|
||||
|
||||
|
||||
//connect database
|
||||
//development
|
||||
const mongoose = require('mongoose');
|
||||
const { error } = require('console');
|
||||
const opportunity = require('./models/opportunity');
|
||||
|
||||
|
||||
mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||
.then(()=>{
|
||||
console.log("Connection Open")
|
||||
})
|
||||
.catch(err =>{
|
||||
console.log("ERROR")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
|
||||
const db = mongoose.connection;
|
||||
db.on("error", console.error.bind(console, "connection error"));
|
||||
db.once("open", ()=>{
|
||||
console.log("Database connected");
|
||||
});
|
||||
|
||||
// const { fetchAspireData } = require('./aspireApi')
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
|
||||
|
||||
// Configure SendGrid with your API key
|
||||
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
|
||||
|
||||
|
||||
app.use(express.static(path.join(__dirname, 'public')))
|
||||
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', path.join(__dirname,'/views'));
|
||||
|
||||
|
||||
//index route
|
||||
app.get('/', (req, res)=>{
|
||||
res.render('home')
|
||||
})
|
||||
//POST Authorize route to gain access
|
||||
app.post('/authorize', async (req, res)=>{
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_API_SECRET_KEY } = process.env;
|
||||
const tokenUrl = 'https://cloud-api.youraspire.com/Authorization';
|
||||
|
||||
const response = await axios.post(tokenUrl, {
|
||||
grant_type: 'client_credentials',
|
||||
ClientId: ASPIRE_API_CLIENT_ID,
|
||||
Secret: ASPIRE_API_SECRET_KEY,
|
||||
});
|
||||
|
||||
return response.data.access_token;
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
//WORK TICKET VISIT ROUTES
|
||||
// api GET WORK TICKET VISITS
|
||||
app.get('/api/workticketvisits', async (req, res) => {
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN, ASPIRE_REFRESH_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/WorkTicketVisits?%24select=WorkTicketVisitID%2CWorkTicketID%2CScheduledDate&%24filter=ScheduledDate%20gt%202024-01-29`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN }`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const workticketvisits = response.data;
|
||||
//save to database before going to client
|
||||
// therefore logic to have databse filter logic beofre going to client
|
||||
|
||||
|
||||
res.render('./workticketvisits', { workticketvisits });
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
//API - GET - WORK TICKETS
|
||||
app.get('/api/worktickets', async (req, res) => {
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN, ASPIRE_REFRESH_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/WorkTickets`;
|
||||
|
||||
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN }`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const workTickets = response.data;
|
||||
// await tickets.save();
|
||||
res.json({ workTickets });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET ALL OPPORTUNITIES
|
||||
app.get('/api/opportunities', async (req, res) => {
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN, ASPIRE_REFRESH_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/opportunities`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const opportunities = response.data;
|
||||
// await tickets.save();
|
||||
res.json({ opportunities });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
//INDEX - GET ALL customer contacts
|
||||
app.get('api/contacts', async (req, res) => {
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_API_SECRET_KEY, ASPIRE_TOKEN, ASPIRE_REFRESH_TOKEN } = process.env;
|
||||
|
||||
// Implement logic to fetch appointment data using Axios and API keys
|
||||
const apiUrl = `https://cloud-api.youraspire.com/Contacts?$filter=ContactTypeName eq 'Customer' and LastName ne 'Employee'&$select=FirstName,LastName,Email,CompanyName`; // Replace with the actual API endpoint
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
|
||||
const contacts = response.data; // Assuming the response directly provides contacts
|
||||
|
||||
|
||||
res.render('contacts', { contacts });
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
//INDEX - GET ALL PROPERTIES
|
||||
app.get('/api/properties', async (req, res) => {
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_API_SECRET_KEY, ASPIRE_TOKEN } = process.env;
|
||||
|
||||
// Implement logic to fetch appointment data using Axios and API keys
|
||||
const apiUrl = `https://cloud-api.youraspire.com/properties`; // Replace with the actual API endpoint
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
|
||||
const properties = response.data; // Assuming the response directly provides properties
|
||||
|
||||
res.render('properties', { properties });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// DB -GET - WORK TICKET VISIT INDEX
|
||||
app.get('/db/workticketvisits', async (req, res) => {
|
||||
const visits = await WorkTicketVisitModel.find({})
|
||||
res.render('./workticketvisits/index', { visits })
|
||||
});
|
||||
//DB - SHOW WORKTICKETVISIT/:ID
|
||||
app.get('/db/workticketvisit/:id', async (req, res) => {
|
||||
const visit = await WorkTicketVisitModel.findById(req.params.id)
|
||||
res.render('./workticketvisits/show', { visit })
|
||||
});
|
||||
|
||||
// DB -GET - WORK TICKET INDEX
|
||||
app.get('/db/worktickets', async (req, res) => {
|
||||
const tickets = await WorkTicketModel.find({})
|
||||
res.render('worktickets/index', { tickets })
|
||||
});
|
||||
//DB - SHOW WORKTICKET/:ID
|
||||
app.get('/db/worktickets/:id', async (req, res) => {
|
||||
const ticket = await WorkTicketModel.findById(req.params.id)
|
||||
|
||||
res.render('./worktickets/show', { ticket });
|
||||
});
|
||||
|
||||
//DB - INDEX GET ALL contacts
|
||||
app.get('/db/contacts', async (req, res) => {
|
||||
const contacts = await ContactModel.find({})
|
||||
res.render('./contacts/index', {contacts });
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**** MESSAGING FEATURE ROUTE ****/
|
||||
app.get('/messages', async (req, res)=>{
|
||||
try {
|
||||
const contacts = await ContactModel.find({});
|
||||
|
||||
const propertyContacts = await PropertyContactModel.find({});
|
||||
|
||||
const properties = await PropertyModel.find({});
|
||||
|
||||
const opportunities = await OpportunityModel.find({});
|
||||
const worktickets = await WorkTicketModel.find({});
|
||||
const workVisits = await WorkTicketVisitModel.find({});
|
||||
|
||||
const filteredContacts = workVisits.filter(visit => {
|
||||
return worktickets.some(ticket => ticket.WorkTicketID === visit.WorkTicketID );
|
||||
}).filter(opportunity => {
|
||||
|
||||
return opportunities.some(wonOpportunity => wonOpportunity.OpportunityID === ticket.OpportunityID && opportunity.OpportunityStatusName === "won");
|
||||
}).filter(propertyContact => {
|
||||
|
||||
return propertyContacts.some(propContact => propContact.PropertyID === wonOpportunity.PropertyID );
|
||||
});
|
||||
|
||||
|
||||
|
||||
res.render('./messages/index', {
|
||||
filteredContacts,
|
||||
// Include other filtered data in the render object
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
//SendGrid TEST - Navigation will need emails to employee contacts in apsire.
|
||||
app.get('/test', async (req, res) => {
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN, SENDGRID_API_KEY } = process.env;
|
||||
|
||||
|
||||
// Implement logic to fetch appointment data using Axios and API keys
|
||||
const apiUrl = `https://cloud-api.youraspire.com/Contacts?$filter=ContactTypeName eq 'Employee' and LastName ne 'Employee'&$select=FirstName,LastName,Email,CompanyName,Salutation`; // Replace with the actual API endpoint
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
|
||||
const contacts = response.data;
|
||||
// Assuming the response directly provides contacts
|
||||
|
||||
// Send personalized emails using SendGrid for each contact retrieved
|
||||
const sgMail = require('@sendgrid/mail');
|
||||
sgMail.setApiKey(SENDGRID_API_KEY);
|
||||
|
||||
contacts.forEach(async (contact) => {
|
||||
const msg = {
|
||||
to: contact.Email,
|
||||
from: 'info@sprinklersnorthwest.com',
|
||||
subject: 'Bulk Email To Employee Contacts', // Set a subject for the email
|
||||
text: `Hi ${contact.FirstName} ${contact.LastName} of ${contact.CompanyName}, This is an bulk email test to confirm I have pulled contact data from the Aspire API and sent it through sendGrid if this is received please respond to my email landry@shilocode.com when possible thank you Landry-Developer-Shiloh Code`,
|
||||
html: `Hi ${contact.FirstName} ${contact.LastName} of ${contact.CompanyName}, This is an bulk email test to confirm I have pulled contact data from the Aspire API and sent it through sendGrid if this is received please respond to my email landry@shilocode.com when possible thank you Landry-Developer-Shiloh Code`,
|
||||
};
|
||||
|
||||
await sgMail.send(msg);
|
||||
});
|
||||
|
||||
res.json({ message: 'Emails sent successfully!' });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on port ${port}`);
|
||||
});
|
29
models/contact.js
Normal file
29
models/contact.js
Normal file
@ -0,0 +1,29 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const ContactScehma = new Schema({
|
||||
ContactID: {
|
||||
type: Number, // Use the Mongoose Schema Type for Number
|
||||
},
|
||||
|
||||
CompanyName: {
|
||||
type: String,
|
||||
},
|
||||
ContactTypeName: {
|
||||
type: String
|
||||
},
|
||||
FirstName: {
|
||||
type: String
|
||||
},
|
||||
LastName: {
|
||||
type: String
|
||||
},
|
||||
Email: {
|
||||
type: String
|
||||
},
|
||||
MobilePhone: {
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Contact', ContactScehma);
|
22
models/opportunity.js
Normal file
22
models/opportunity.js
Normal file
@ -0,0 +1,22 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const OpportunityScehma = new Schema({
|
||||
OpportunityID: {
|
||||
type: Number, // Use the Mongoose Schema Type for Number
|
||||
},
|
||||
|
||||
PropertyID: {
|
||||
type: Number,
|
||||
},
|
||||
|
||||
OpportunityStatusName: {
|
||||
type: String
|
||||
},
|
||||
|
||||
BranchName: {
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Opportunity', OpportunityScehma);
|
34
models/property.js
Normal file
34
models/property.js
Normal file
@ -0,0 +1,34 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const PropertyScehma = new Schema({
|
||||
PropertyID: {
|
||||
type: Number, // Use the Mongoose Schema Type for Number
|
||||
},
|
||||
|
||||
PropertyAddressLine1: {
|
||||
type: String,
|
||||
},
|
||||
PropertyAddressLine2: {
|
||||
type: String,
|
||||
},
|
||||
PropertyAddressCity: {
|
||||
type: String,
|
||||
},
|
||||
PropertyAddressStateProvinceCode: {
|
||||
type: String,
|
||||
},
|
||||
|
||||
PropertyAddressZipCode: {
|
||||
type: String
|
||||
},
|
||||
PropertyStatusName: {
|
||||
type: String
|
||||
},
|
||||
|
||||
BranchName: {
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Property', PropertyScehma);
|
21
models/propertyContact.js
Normal file
21
models/propertyContact.js
Normal file
@ -0,0 +1,21 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const PropertyContactScehma = new Schema({
|
||||
PropertyID: {
|
||||
type: Number, // Use the Mongoose Schema Type for Number
|
||||
},
|
||||
|
||||
ContactName: {
|
||||
type: String,
|
||||
},
|
||||
ContactID: {
|
||||
type: Number
|
||||
},
|
||||
CompanyName: {
|
||||
type: String
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('PropertyContact', PropertyContactScehma);
|
26
models/workticket.js
Normal file
26
models/workticket.js
Normal file
@ -0,0 +1,26 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const WorkTicketScehma = new Schema({
|
||||
WorkTicketID: {
|
||||
type: Number, // Use the Mongoose Schema Type for Number
|
||||
},
|
||||
|
||||
Price:{
|
||||
type: String,
|
||||
},
|
||||
OpportunityID: {
|
||||
type: Number
|
||||
},
|
||||
WorkTicketStatusName:{
|
||||
type: String
|
||||
},
|
||||
ScheduledStartDate:{
|
||||
type: Date
|
||||
},
|
||||
BranchName:{
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('WorkTicket', WorkTicketScehma);
|
20
models/workticketvisit.js
Normal file
20
models/workticketvisit.js
Normal file
@ -0,0 +1,20 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const WorkTicketVisitScehma = new Schema({
|
||||
WorkTicketVisitID: {
|
||||
type: Number, // Use the Mongoose Schema Type for Number
|
||||
},
|
||||
WorkTicketID: {
|
||||
type: Number, // Use the Mongoose Schema Type for Number
|
||||
|
||||
},
|
||||
ScheduledDate:{
|
||||
type: String,
|
||||
},
|
||||
RouteName:{
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('WorkTicketVisit', WorkTicketVisitScehma);
|
1839
package-lock.json
generated
Normal file
1839
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
package.json
Normal file
29
package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "brotherton-aspire-webapp",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node ./bin/www"
|
||||
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@sendgrid/mail": "^8.1.0",
|
||||
"axios": "^1.6.5",
|
||||
"body-parser": "^1.20.2",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"dotenv": "^16.3.1",
|
||||
"ejs": "^3.1.9",
|
||||
"express": "^4.18.2",
|
||||
"mongoose": "^8.1.0",
|
||||
"morgan": "^1.10.0",
|
||||
"passport": "^0.7.0",
|
||||
"serve-favicon": "^2.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"locus": "^2.0.4"
|
||||
}
|
||||
}
|
6
public/css/bootstrap.min.css
vendored
Normal file
6
public/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
public/js/bootstrap.min.js
vendored
Normal file
7
public/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/jquery.js
vendored
Normal file
2
public/js/jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
67
seeds/contact.js
Normal file
67
seeds/contact.js
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
require('dotenv').config();
|
||||
const axios = require('axios');
|
||||
//connect database
|
||||
//development
|
||||
const mongoose = require('mongoose');
|
||||
const Contact = require('../models/contact');
|
||||
|
||||
mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||
.then(() => {
|
||||
console.log("Connection Open")
|
||||
})
|
||||
.catch(err => {
|
||||
console.log("ERROR")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
|
||||
const db = mongoose.connection;
|
||||
db.on("error", console.error.bind(console, "connection error"));
|
||||
db.once("open", () => {
|
||||
console.log("Database connected");
|
||||
});
|
||||
|
||||
const seedDB = async () => {
|
||||
await Contact.deleteMany({});
|
||||
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/Contacts?%24select=ContactID%2CCompanyName%2CContactTypeName%2CFirstName%2CLastName%2CEmail%2CMobilePhone`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const contactArray = response.data
|
||||
|
||||
//save to database before going to client
|
||||
// therefore logic to have databse filter logic beofre going to client
|
||||
// await contacts.save();
|
||||
// Save each work ticket visit to the database
|
||||
for (const contactPerson of contactArray) {
|
||||
const contact = new Contact({
|
||||
ContactID: contactPerson.ContactID,
|
||||
CompanyName: contactPerson.CompanyName,
|
||||
ContactTypeName: contactPerson.ContactTypeName,
|
||||
FirstName: contactPerson.FirstName,
|
||||
LastName: contactPerson.LastName,
|
||||
Email: contactPerson.Email,
|
||||
MobilePhone: contactPerson.MobilePhone,
|
||||
|
||||
});
|
||||
|
||||
await contact.save();
|
||||
}
|
||||
|
||||
console.log('Seeding completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Seeding error:', error.message);
|
||||
} finally {
|
||||
// Close the database connection after seeding
|
||||
mongoose.connection.close();
|
||||
}
|
||||
};
|
||||
|
||||
seedDB();
|
63
seeds/index.js
Normal file
63
seeds/index.js
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
require('dotenv').config();
|
||||
const axios = require('axios');
|
||||
//connect database
|
||||
//development
|
||||
const mongoose = require('mongoose');
|
||||
const WorkTicketVisits = require('../models/workticketvisit');
|
||||
|
||||
mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||
.then(() => {
|
||||
console.log("Connection Open")
|
||||
})
|
||||
.catch(err => {
|
||||
console.log("ERROR")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
|
||||
const db = mongoose.connection;
|
||||
db.on("error", console.error.bind(console, "connection error"));
|
||||
db.once("open", () => {
|
||||
console.log("Database connected");
|
||||
});
|
||||
|
||||
const seedDB = async () => {
|
||||
await WorkTicketVisits.deleteMany({});
|
||||
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/WorkTicketVisits?%24select=WorkTicketVisitID%2CWorkTicketID%2CRouteName%2CScheduledDate&%24filter=ScheduledDate%20gt%202024-01-29`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const workticketvisitsArray = response.data
|
||||
|
||||
//save to database before going to client
|
||||
// therefore logic to have databse filter logic beofre going to client
|
||||
// await workticketvisits.save();
|
||||
// Save each work ticket visit to the database
|
||||
for (const workticketvisit of workticketvisitsArray) {
|
||||
const visit = new WorkTicketVisits({
|
||||
WorkTicketVisitID: workticketvisit.WorkTicketVisitID,
|
||||
WorkTicketID: workticketvisit.WorkTicketID,
|
||||
ScheduledDate: workticketvisit.ScheduledDate,
|
||||
RouteName: workticketvisit.RouteName
|
||||
});
|
||||
|
||||
await visit.save();
|
||||
}
|
||||
|
||||
console.log('Seeding completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Seeding error:', error.message);
|
||||
} finally {
|
||||
// Close the database connection after seeding
|
||||
mongoose.connection.close();
|
||||
}
|
||||
};
|
||||
|
||||
seedDB();
|
65
seeds/opportunity.js
Normal file
65
seeds/opportunity.js
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
require('dotenv').config();
|
||||
const axios = require('axios');
|
||||
//connect database
|
||||
//development
|
||||
const mongoose = require('mongoose');
|
||||
const Opportunity = require('../models/opportunity');
|
||||
|
||||
mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||
.then(() => {
|
||||
console.log("Connection Open")
|
||||
})
|
||||
.catch(err => {
|
||||
console.log("ERROR")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
|
||||
const db = mongoose.connection;
|
||||
db.on("error", console.error.bind(console, "connection error"));
|
||||
db.once("open", () => {
|
||||
console.log("Database connected");
|
||||
});
|
||||
|
||||
const seedDB = async () => {
|
||||
await Opportunity.deleteMany({});
|
||||
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/Opportunities?%24select=OpportunityID%2CPropertyID%2COpportunityStatusName%2CBranchName&%24filter=OpportunityStatusName%20eq%20%27won%27`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const opportunityArray = response.data
|
||||
|
||||
//save to database before going to client
|
||||
// therefore logic to have databse filter logic beofre going to client
|
||||
// await contacts.save();
|
||||
// Save each work ticket visit to the database
|
||||
for (const wonOpportunity of opportunityArray) {
|
||||
const opportunity = new Opportunity({
|
||||
OpportunityID: wonOpportunity.OpportunityID,
|
||||
PropertyID: wonOpportunity.PropertyID,
|
||||
OpportunityStatusName: wonOpportunity.OpportunityStatusName,
|
||||
BranchName: wonOpportunity.BranchName,
|
||||
|
||||
|
||||
});
|
||||
|
||||
await opportunity.save();
|
||||
}
|
||||
|
||||
console.log('Seeding completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Seeding error:', error.message);
|
||||
} finally {
|
||||
// Close the database connection after seeding
|
||||
mongoose.connection.close();
|
||||
}
|
||||
};
|
||||
|
||||
seedDB();
|
67
seeds/property.js
Normal file
67
seeds/property.js
Normal file
@ -0,0 +1,67 @@
|
||||
require('dotenv').config();
|
||||
const axios = require('axios');
|
||||
//connect database
|
||||
//development
|
||||
const mongoose = require('mongoose');
|
||||
const Property = require('../models/property');
|
||||
|
||||
mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||
.then(() => {
|
||||
console.log("Connection Open")
|
||||
})
|
||||
.catch(err => {
|
||||
console.log("ERROR")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
|
||||
const db = mongoose.connection;
|
||||
db.on("error", console.error.bind(console, "connection error"));
|
||||
db.once("open", () => {
|
||||
console.log("Database connected");
|
||||
});
|
||||
|
||||
const seedDB = async () => {
|
||||
await Property.deleteMany({});
|
||||
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/Properties?%24select=PropertyID%2CBranchName%2CPropertyStatusName%2CPropertyAddressLine1%2CPropertyAddressLine2%2CPropertyAddressCity%2CPropertyAddressStateProvinceCode%2CPropertyAddressZipCode`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const propertyArray = response.data
|
||||
|
||||
//save to database before going to client
|
||||
// therefore logic to have databse filter logic beofre going to client
|
||||
// await contacts.save();
|
||||
// Save each work ticket visit to the database
|
||||
for (const propertyData of propertyArray) {
|
||||
const property = new Property({
|
||||
PropertyID: propertyData.PropertyID,
|
||||
PropertyAddressLine1: propertyData.PropertyAddressLine1,
|
||||
PropertyAddressLine2: propertyData.PropertyAddressLine2,
|
||||
PropertyAddressCity: propertyData.PropertyAddressCity,
|
||||
PropertyAddressStateProvinceCode: propertyData.PropertyAddressStateProvinceCode,
|
||||
PropertyAddressZipCode: propertyData.PropertyAddressZipCode,
|
||||
PropertyStatusName: propertyData.PropertyStatusName,
|
||||
BranchName: propertyData.BranchName,
|
||||
|
||||
});
|
||||
|
||||
await property.save();
|
||||
}
|
||||
|
||||
console.log('Seeding completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Seeding error:', error.message);
|
||||
} finally {
|
||||
// Close the database connection after seeding
|
||||
mongoose.connection.close();
|
||||
}
|
||||
};
|
||||
|
||||
seedDB();
|
64
seeds/propertyContact.js
Normal file
64
seeds/propertyContact.js
Normal file
@ -0,0 +1,64 @@
|
||||
require('dotenv').config();
|
||||
const axios = require('axios');
|
||||
//connect database
|
||||
//development
|
||||
const mongoose = require('mongoose');
|
||||
const PropertyContact = require('../models/propertyContact');
|
||||
|
||||
mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||
.then(() => {
|
||||
console.log("Connection Open")
|
||||
})
|
||||
.catch(err => {
|
||||
console.log("ERROR")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
|
||||
const db = mongoose.connection;
|
||||
db.on("error", console.error.bind(console, "connection error"));
|
||||
db.once("open", () => {
|
||||
console.log("Database connected");
|
||||
});
|
||||
|
||||
const seedDB = async () => {
|
||||
await PropertyContact.deleteMany({});
|
||||
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/PropertyContacts?%24select=PropertyID%2CContactID%2CContactName%2CCompanyName`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const propertyArray = response.data
|
||||
|
||||
//save to database before going to client
|
||||
// therefore logic to have databse filter logic beofre going to client
|
||||
// await contacts.save();
|
||||
// Save each work ticket visit to the database
|
||||
for (const propertyContactData of propertyArray) {
|
||||
const property = new PropertyContact({
|
||||
PropertyID: propertyContactData.PropertyID,
|
||||
ContactName: propertyContactData.ContactName,
|
||||
ContactID: propertyContactData.ContactID,
|
||||
CompanyName: propertyContactData.CompanyName,
|
||||
|
||||
|
||||
});
|
||||
|
||||
await property.save();
|
||||
}
|
||||
|
||||
console.log('Seeding completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Seeding error:', error.message);
|
||||
} finally {
|
||||
// Close the database connection after seeding
|
||||
mongoose.connection.close();
|
||||
}
|
||||
};
|
||||
|
||||
seedDB();
|
65
seeds/workticketseed.js
Normal file
65
seeds/workticketseed.js
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
require('dotenv').config();
|
||||
const axios = require('axios');
|
||||
//connect database
|
||||
//development
|
||||
const mongoose = require('mongoose');
|
||||
const WorkTickets = require('../models/workticket');
|
||||
|
||||
mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||
.then(() => {
|
||||
console.log("Connection Open")
|
||||
})
|
||||
.catch(err => {
|
||||
console.log("ERROR")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
|
||||
const db = mongoose.connection;
|
||||
db.on("error", console.error.bind(console, "connection error"));
|
||||
db.once("open", () => {
|
||||
console.log("Database connected");
|
||||
});
|
||||
|
||||
const seedDB = async () => {
|
||||
await WorkTickets.deleteMany({});
|
||||
|
||||
try {
|
||||
const { ASPIRE_API_CLIENT_ID, ASPIRE_TOKEN, ASPIRE_REFRESH_TOKEN } = process.env;
|
||||
const apiUrl = `https://cloud-api.youraspire.com/WorkTickets?%24select=OpportunityID%2CPrice%2CWorkTicketID%2CBranchName%2CWorkTicketStatusName%2CScheduledStartDate&%24filter=WorkTicketStatusName%20eq%20%27Open%27`;
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${ASPIRE_TOKEN}`,
|
||||
'Client-ID': ASPIRE_API_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
const response = await axios.get(apiUrl, { headers });
|
||||
const workticketArray = response.data
|
||||
|
||||
//save to database before going to client
|
||||
// therefore logic to have databse filter logic beofre going to client
|
||||
// await worktickets.save();
|
||||
// Save each work ticket to the database
|
||||
for (const workticket of workticketArray) {
|
||||
const ticket = new WorkTickets({
|
||||
WorkTicketID: workticket.WorkTicketID,
|
||||
Notes: workticket.Notes,
|
||||
OpportunityServiceID: workticket.OpportunityServiceID,
|
||||
OpportunityID: workticket.OpportunityID,
|
||||
WorkTicketStatusName: workticket.WorkTicketStatusName,
|
||||
ScheduledStartDate: workticket.ScheduledStartDate
|
||||
});
|
||||
|
||||
await ticket.save();
|
||||
}
|
||||
|
||||
console.log('Seeding completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Seeding error:', error.message);
|
||||
} finally {
|
||||
// Close the database connection after seeding
|
||||
mongoose.connection.close();
|
||||
}
|
||||
};
|
||||
|
||||
seedDB();
|
14
views/contacts.ejs
Normal file
14
views/contacts.ejs
Normal file
@ -0,0 +1,14 @@
|
||||
<%- include('partials/head') -%>
|
||||
|
||||
<%- include ('partials/navbar') %>
|
||||
|
||||
<h1>Contacts</h1>
|
||||
<ul>
|
||||
<% for (let contact of contacts) { %>
|
||||
<li>
|
||||
<%= contact.FirstName %>
|
||||
</li>
|
||||
<% } %>
|
||||
</ul>
|
||||
|
||||
<%- include ('partials/footer') %>
|
24
views/contacts/index.ejs
Normal file
24
views/contacts/index.ejs
Normal file
@ -0,0 +1,24 @@
|
||||
<%- include('../partials/head') %>
|
||||
|
||||
<%- include ('../partials/navbar') %>
|
||||
<h1>Contacts</h1>
|
||||
|
||||
|
||||
|
||||
<ul>
|
||||
<% for (let contact of contacts){%>
|
||||
<li>
|
||||
<a href="/contact/<%= contact._id %>">
|
||||
<%= contact.CompanyName %>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
<%= contact.ContactID %>
|
||||
</li>
|
||||
|
||||
|
||||
<% }%>
|
||||
</ul>
|
||||
|
||||
<%- include ('../partials/footer') %>
|
3
views/error.ejs
Normal file
3
views/error.ejs
Normal file
@ -0,0 +1,3 @@
|
||||
<h1><%= message %></h1>
|
||||
<h2><%= error.status %></h2>
|
||||
<pre><%= error.stack %></pre>
|
6
views/home.ejs
Normal file
6
views/home.ejs
Normal file
@ -0,0 +1,6 @@
|
||||
<%- include('partials/head') %>
|
||||
|
||||
<%- include ('partials/navbar') %>
|
||||
<h1>Index Page</h1>
|
||||
|
||||
<%- include ('partials/footer') %>
|
12
views/index.ejs
Normal file
12
views/index.ejs
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><%= title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<h1><%= title %></h1>
|
||||
<p>Welcome to <%= title %></p>
|
||||
</body>
|
||||
</html>
|
17
views/messages/index.ejs
Normal file
17
views/messages/index.ejs
Normal file
@ -0,0 +1,17 @@
|
||||
<%- include('../partials/head') -%>
|
||||
|
||||
<%- include ('../partials/navbar') %>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Display filtered contacts -->
|
||||
<h2>Filtered Contacts</h2>
|
||||
<ul>
|
||||
<% filteredContacts.forEach(contact => { %>
|
||||
<li><%= contact.FirstName %></li>
|
||||
|
||||
<% }); %>
|
||||
</ul>
|
||||
|
||||
<%- include ('../partials/footer') %>
|
0
views/opportunities/index.ejs
Normal file
0
views/opportunities/index.ejs
Normal file
5
views/partials/footer.ejs
Normal file
5
views/partials/footer.ejs
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
<footer>footer</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
14
views/partials/head.ejs
Normal file
14
views/partials/head.ejs
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Brotherton Aspire Messaging App</title>
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<script src="/js/jquery.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
45
views/partials/navbar.ejs
Normal file
45
views/partials/navbar.ejs
Normal file
@ -0,0 +1,45 @@
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Brotherton Aspire App</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/api/contacts">API Contacts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/db/contacts">DB Contacts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/properties">Properties</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/api/worktickets"> API Work Tickets</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/api/workticketvisits">API - Work Ticket Vistis</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/workticketvisits">DB - Work Tickets Visits</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/worktickets"> DB Work Tickets</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/messages"> Messages</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/opportunities">opportunities</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
14
views/properties.ejs
Normal file
14
views/properties.ejs
Normal file
@ -0,0 +1,14 @@
|
||||
<%- include('partials/head') -%>
|
||||
|
||||
<%- include ('partials/navbar') %>
|
||||
|
||||
<h1>properties</h1>
|
||||
<ul>
|
||||
<% for (let property of properties) { %>
|
||||
<li>
|
||||
<%= property.PropertyName %>
|
||||
</li>
|
||||
<% } %>
|
||||
</ul>
|
||||
|
||||
<%- include ('partials/footer') %>
|
0
views/properties/index.ejs
Normal file
0
views/properties/index.ejs
Normal file
0
views/propertyContacts/index.ejs
Normal file
0
views/propertyContacts/index.ejs
Normal file
29
views/worktickets/index.ejs
Normal file
29
views/worktickets/index.ejs
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>work ticket indes</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Work Tickets</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
<ul>
|
||||
<% for (let ticket of tickets){%>
|
||||
<li>
|
||||
<a href="/worktickets/<%= ticket._id %>">
|
||||
<%= ticket.WorkTicketID %>
|
||||
</a>
|
||||
</li>
|
||||
<% }%>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
27
views/worktickets/show.ejs
Normal file
27
views/worktickets/show.ejs
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>work ticket show</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Show work ticket details</h1>
|
||||
<h3>
|
||||
Ticket ID
|
||||
<%= ticket.WorkTicketID %>
|
||||
</h3>
|
||||
<h4>
|
||||
status
|
||||
<%= ticket.WorkTicketStatusName %>
|
||||
</h4>
|
||||
|
||||
<p>
|
||||
<%= ticket.SceduledStartDate %>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
27
views/workticketvisits/index.ejs
Normal file
27
views/workticketvisits/index.ejs
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>work ticket index</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Work Ticket Visits</h1>
|
||||
|
||||
|
||||
<ul>
|
||||
<% for (let visit of workticketvisits){%>
|
||||
<li>
|
||||
<a href="/workticketvisit/<%= visit._id %>">
|
||||
<%= visit.WorkTicketVisitID %>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<% }%>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
20
views/workticketvisits/show.ejs
Normal file
20
views/workticketvisits/show.ejs
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SHOW work ticket visits </title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3>Vistit ID
|
||||
<%= visit.WorkTicketVisitID %></h3>
|
||||
|
||||
<h1><%= visit.RouteName %></h1>
|
||||
<h2><%= visit.WorkTicketID %></h2>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
33
views/workticketvisits/workticketvisits.ejs
Normal file
33
views/workticketvisits/workticketvisits.ejs
Normal file
@ -0,0 +1,33 @@
|
||||
<%- include('/partials/head') %>
|
||||
|
||||
<%- include ('partials/navbar') %>
|
||||
<h1>Work Ticket Visits</h1>
|
||||
|
||||
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Work Ticket ID</th>
|
||||
<th scope="col">Scheduled Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for (let i=0; i < workticketvisits.length; i++) { %>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<%= i + 1 %>
|
||||
</th>
|
||||
<td>
|
||||
<%= workticketvisits[i].WorkTicketID %>
|
||||
</td>
|
||||
<td>
|
||||
<%= workticketvisits[i].ScheduledDate %>
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%- include ('partials/footer') %>
|
Loading…
Reference in New Issue
Block a user