├── credentials.json ├── .gitignore ├── src ├── public │ ├── views │ │ ├── events.html │ │ └── index.html │ └── css │ │ └── app.css └── app.js ├── package.json ├── SECURITY.md └── README.md /credentials.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | config -------------------------------------------------------------------------------- /src/public/views/events.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Google Events 8 | 9 | 10 |
11 |

Your event is created successfully.

12 |

You can see it in your Google Calender

13 |
14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "google-calender", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "engines": { 7 | "node": "13.10.1" 8 | }, 9 | "dependencies": { 10 | "@sendgrid/mail": "^7.4.0", 11 | "axios": "^0.21.1", 12 | "ejs": "^3.1.7", 13 | "express": "^4.17.1", 14 | "googleapis": "^39.2.0", 15 | "json-bigint": "^1.0.0", 16 | "node-forge": "^0.10.0", 17 | "node-json2html": "^1.4.0", 18 | "nodemon": "^2.0.3" 19 | }, 20 | "devDependencies": {}, 21 | "scripts": { 22 | "start": "node src/app.js", 23 | "dev": "env-cmd -f ./config/dev.env node src/app.js" 24 | }, 25 | "author": "", 26 | "license": "ISC" 27 | } 28 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /src/public/css/app.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background-color: #4CAF50; 3 | border: none; 4 | color: white; 5 | padding: 15px 32px; 6 | text-align: center; 7 | text-decoration: none; 8 | display: inline-block; 9 | font-size: 16px; 10 | margin: 4px 2px; 11 | cursor: pointer; 12 | } 13 | 14 | .form { 15 | margin: 0 200px; 16 | border-radius: 5px; 17 | background-color: #f2f2f2; 18 | padding: 15px 30px; 19 | } span { 20 | color: red; 21 | margin-left: 20px; 22 | } 23 | 24 | input[type=email], 25 | input[type=text], 26 | select { 27 | width: 100%; 28 | padding: 12px 20px; 29 | margin: 8px 0; 30 | display: inline-block; 31 | border: 1px solid #ccc; 32 | border-radius: 4px; 33 | box-sizing: border-box; 34 | } 35 | input[type=submit] { 36 | width: 100%; 37 | background-color: #4CAF50; 38 | color: white; 39 | padding: 14px 20px; 40 | margin: 15px 0; 41 | border: none; 42 | border-radius: 4px; 43 | cursor: pointer; 44 | } 45 | input[type=submit]:hover { 46 | background-color: #45a049; 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoogleCalender 2 | 3 | 4 | ***************************************************** 5 | ****************** IMPORTANT ************************ 6 | 7 | 8 | Make YOUR OWN credentials.json file BEFORE running the code 9 | 10 | Watch video: The Google Calendar API (PART 1) 11 | 12 | Time: 13:20 - Google Calendar API and credentials.json 13 | 14 | 15 | ****************** IMPORTANT ************************ 16 | ***************************************************** 17 | 18 | 19 | How this Project works? https://www.youtube.com/watch?v=K2JD61PZ-8U&list=PLcL8q_TiioW3FxvmlatZlTZQCnRs_UMoG 20 | 21 | 22 | This project is made by GOOGLE SEARCH API, SENDGRID and GOOGLE DEVELOPER CONSOLE. 23 | 24 | Run the Google Calender App on the Browser by installing the repo code and running following commands on the BASH terminal: 25 | 26 | 1 --> cd GoogleCalender-master 27 | 28 | 2 --> npm i express env-cmd 29 | 30 | 3 --> make a config folder in the root directory and inside it make a 'dev.env' file like as config(folder) -> dev.env(file) .The config file must contain 4 env variables as: 31 | 32 | SENDGRID_API_KEY=your sendgrid api key 33 | 34 | CLIENT_ID=your google api client id 35 | 36 | CLIENT_SECRET=your google client secret 37 | 38 | REFRESH_TOKEN=your developer refresh token 39 | 40 | 41 | 4 --> npm run dev 42 | 43 | 5 --> Open the Google Calender app in your browser. 44 | -------------------------------------------------------------------------------- /src/public/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Google Calander 6 | 7 | 8 | 9 |
10 |
11 | Sign In 12 | You need to Sign In first

13 | 14 | 15 | 16 |
17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 | 29 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | /* 2 | Make YOUR OWN credentials.json file BEFORE running the CODE 3 | 4 | Watch video: The Google Calendar API (PART 1) 5 | 6 | Time: 13:20 - Google Calendar API and credentials.json 7 | 8 | */ 9 | 10 | // NEW COMMIT 11 | 12 | const express = require('express') 13 | const app = express() 14 | const path = require('path') 15 | const bodyParser = require('body-parser'); 16 | 17 | var var_arr=['Extracting finished. Refresh the browser to see your Google events']; 18 | 19 | app.use(express.static(path.join(__dirname, 'public'))) 20 | app.set('views', __dirname + '/public/views'); 21 | app.engine('html', require('ejs').renderFile); 22 | app.set('view engine', 'html'); 23 | app.use(bodyParser.urlencoded({extended: true})); 24 | app.use(bodyParser.json()); 25 | 26 | app.get('/', (req, res) =>{ 27 | res.render('index.html'); 28 | }) 29 | 30 | app.post('/', (req, res) => { 31 | const tkn=req.body.token; 32 | const fs = require('fs'); 33 | const {google} = require('googleapis'); 34 | 35 | const SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']; 36 | // The file token.json stores the user's access and refresh tokens, and is 37 | // created automatically when the authorization flow completes for the first 38 | // time. 39 | const TOKEN_PATH = 'token.json'; 40 | 41 | // Load client secrets from a local file. 42 | fs.readFile('credentials.json', (err, content) => { 43 | if (err) return console.log('Error loading client secret file:', err); 44 | // Authorize a client with credentials, then call the Google Calendar API. 45 | authorize(JSON.parse(content), listEvents); 46 | }); 47 | 48 | /** 49 | * Create an OAuth2 client with the given credentials, and then execute the 50 | * given callback function. 51 | * @param {Object} credentials The authorization client credentials. 52 | * @param {function} callback The callback to call with the authorized client. 53 | */ 54 | function authorize(credentials, callback) { 55 | const {client_secret, client_id, redirect_uris} = credentials.installed; 56 | const oAuth2Client = new google.auth.OAuth2( 57 | client_id, client_secret, redirect_uris[0]); 58 | 59 | // Check if we have previously stored a token. 60 | fs.readFile(TOKEN_PATH, (err, token) => { 61 | if (err) return getAccessToken(oAuth2Client, callback); 62 | oAuth2Client.setCredentials(JSON.parse(token)); 63 | callback(oAuth2Client); 64 | }); 65 | } 66 | 67 | /** 68 | * Get and store new token after prompting for user authorization, and then 69 | * execute the given callback with the authorized OAuth2 client. 70 | * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for. 71 | * @param {getEventsCallback} callback The callback for the authorized client. 72 | */ 73 | function getAccessToken(oAuth2Client, callback) { 74 | oAuth2Client.getToken(tkn, (err, token) => { 75 | if (err) return console.error('Error retrieving access token', err); 76 | oAuth2Client.setCredentials(token); 77 | // Store the token to disk for later program executions 78 | fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => { 79 | if (err) return console.error(err); 80 | console.log('Token stored to', TOKEN_PATH); 81 | }); 82 | callback(oAuth2Client); 83 | }); 84 | } 85 | 86 | /** 87 | * Lists the next events on the user's primary calendar. 88 | * @param {google.auth.OAuth2} auth An authorized OAuth2 client. 89 | */ 90 | function listEvents(auth) { 91 | async function fun(){ 92 | const calendar = await google.calendar({version: 'v3', auth}); 93 | calendar.events.list({ 94 | calendarId: 'primary', 95 | timeMin: (new Date()).toISOString(), 96 | maxResults: 30, 97 | singleEvents: true, 98 | orderBy: 'startTime', 99 | }, (err, res) => { 100 | if (err) return console.log('The API returned an error: ' + err); 101 | const events = res.data.items; 102 | if (events.length) { 103 | console.log('Your upcoming events:', events); 104 | events.map((event, i) => { 105 | var_arr.push(event); 106 | }); 107 | } else { 108 | console.log('No upcoming events found.'); 109 | } 110 | }); 111 | } 112 | fun() 113 | } 114 | res.send(var_arr) 115 | res.render('index.html') 116 | }); 117 | 118 | 119 | app.post('/events', (req, res) =>{ 120 | // Require google from googleapis package. 121 | const { google } = require('googleapis') 122 | // Require oAuth2 from our google instance. 123 | const { OAuth2 } = google.auth 124 | 125 | // Create a new instance of oAuth and set our Client ID & Client Secret. 126 | const oAuth2Client = new OAuth2(process.env.CLIENT_ID, process.env.CLIENT_SECRET) 127 | 128 | // Call the setCredentials method on our oAuth2Client instance and set our refresh token. 129 | oAuth2Client.setCredentials({ 130 | refresh_token: process.env.REFRESH_TOKEN, 131 | }) 132 | 133 | // Create a new calender instance. 134 | const calendar = google.calendar({ version: 'v3', auth: oAuth2Client }) 135 | 136 | // Create a new event start date instance for temp uses in our calendar. 137 | const eventStartTime = new Date() 138 | eventStartTime.setDate(eventStartTime.getDay() + 2) 139 | 140 | // Create a new event end date instance for temp uses in our calendar. 141 | const eventEndTime = new Date() 142 | eventEndTime.setDate(eventEndTime.getDay() + 2) 143 | eventEndTime.setMinutes(eventEndTime.getMinutes() + 60) 144 | 145 | // Create a dummy event for temp uses in our calendar 146 | const event = { 147 | summary: `${req.body.summary}`, 148 | description: `${req.body.description}`, 149 | colorId: 6, 150 | start: { 151 | dateTime: eventStartTime, 152 | }, 153 | end: { 154 | dateTime: eventEndTime, 155 | }, 156 | } 157 | 158 | // Check if we a busy and have an event on our calendar for the same time. 159 | calendar.freebusy.query( 160 | { 161 | resource: { 162 | timeMin: eventStartTime, 163 | timeMax: eventEndTime, 164 | items: [{ id: 'primary' }], 165 | }, 166 | }, 167 | (err, res) => { 168 | // Check for errors in our query and log them if they exist. 169 | if (err) return console.error('Free Busy Query Error: ', err) 170 | 171 | // Create an array of all events on our calendar during that time. 172 | const eventArr = res.data.calendars.primary.busy 173 | 174 | // Check if event array is empty which means we are not busy 175 | if (eventArr.length === 0) { 176 | // If we are not busy create a new calendar event. 177 | return calendar.events.insert( 178 | { calendarId: 'primary', resource: event }, 179 | err => { 180 | // Check for errors and log them if they exist. 181 | if (err) return console.error('Error Creating Calender Event:', err) 182 | // Else log that the event was created. 183 | return console.log('Event created successfully.') 184 | }) 185 | } 186 | // If event array is not empty log that we are busy. 187 | return console.log(`Sorry I'm busy for that time...`) 188 | } 189 | ) 190 | console.log(req.body) 191 | const sgMail = require('@sendgrid/mail') 192 | sgMail.setApiKey(process.env.SENDGRID_API_KEY) 193 | const msg = { 194 | to: req.body.to, // Change to your recipient 195 | from: 'your email goes here', // Change to your verified sender 196 | subject: req.body.summary, 197 | text: req.body.description, 198 | html: req.body.description, 199 | } 200 | sgMail 201 | .send(msg) 202 | .then(() => { 203 | console.log('Email sent') 204 | }) 205 | .catch((error) => { 206 | console.error(error) 207 | }) 208 | 209 | res.render('events.html') 210 | }) 211 | 212 | app.listen(3000, () =>{ 213 | console.log('Server running on port 3000') 214 | }) --------------------------------------------------------------------------------