Skip to content

Commit af1fed6

Browse files
61 Implements google calendar integration backend
1 parent 98ce23e commit af1fed6

File tree

7 files changed

+271
-3
lines changed

7 files changed

+271
-3
lines changed

app.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,56 @@
11
require('./config/mongoose')
22
const express = require('express')
3+
const cors = require('cors')
34
const logger = require('morgan')
45
const cookieParser = require('cookie-parser')
56
const createError = require('http-errors')
67
const path = require('path')
78

9+
const passport = require('passport')
10+
// const passportAuthentication = require('./config/passport')
11+
812
const indexRouter = require('./app/routes/index')
913
const authRouter = require('./app/routes/auth')
1014
const usersRouter = require('./app/routes/user')
1115
const postRouter = require('./app/routes/post')
1216
const shortUrlRouter = require('./app/routes/urlShortner')
17+
const oauthRouter = require('./app/routes/oauth')
18+
const calendarRoute = require('./app/routes/calendar')
1319

1420
const app = express()
1521

1622
// view engine setup
1723
app.set('views', path.join(__dirname, 'views'))
1824
app.set('view engine', 'ejs')
1925

26+
app.use(cors())
2027
app.use(logger('tiny'))
2128
app.use(express.json())
2229
app.use(express.urlencoded({ extended: false }))
2330
app.use(cookieParser())
2431
app.use(express.static(path.join(__dirname, 'public')))
2532

33+
app.use(
34+
require('express-session')({
35+
secret: 'keyboard cat',
36+
resave: true,
37+
saveUninitialized: true
38+
})
39+
)
40+
app.use(passport.initialize())
41+
app.use(passport.session())
42+
2643
app.use('/', indexRouter)
2744
app.use('/auth', authRouter)
2845
app.use('/user', usersRouter)
2946
app.use('/post', postRouter)
3047
app.use('/shortUrl', shortUrlRouter)
48+
app.use('/oauth', oauthRouter)
49+
app.use('/calendar', calendarRoute)
3150

3251
// catch 404 and forward to error handler
3352
app.use(function (req, res, next) {
34-
next(createError(404, 'route doesn\'t exist'))
53+
next(createError(404, "route doesn't exist"))
3554
})
3655

3756
// error handler

app/models/GoogleUser.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const mongoose = require('mongoose')
2+
const Schema = mongoose.Schema
3+
4+
const googleUserSchema = new Schema({
5+
username: String,
6+
googleId: String,
7+
token: String,
8+
refreshToken: String
9+
})
10+
11+
const GoogleUser = mongoose.model('googleuser', googleUserSchema)
12+
13+
module.exports = GoogleUser

app/routes/calendar.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
var express = require('express')
2+
var router = express.Router()
3+
var gcal = require('google-calendar')
4+
const refresh = require('passport-oauth2-refresh')
5+
const GoogleUser = require('../models/GoogleUser')
6+
const tokenUtils = require('../utils/token-utils')
7+
8+
// POST
9+
// /calendar/list
10+
// Returns a list of calendar objects for a given user
11+
router.post('/list', (req, res) => {
12+
// const accessToken = req.body.token;
13+
const googleId = req.body.googleId
14+
15+
tokenUtils.getToken(googleId).then(accessToken => {
16+
const googleCalendar = new gcal.GoogleCalendar(accessToken)
17+
18+
googleCalendar.calendarList.list(function (err, data) {
19+
if (err) {
20+
GoogleUser.findOne({ googleId: googleId }, (err, user) => {
21+
if (err) {
22+
res.json(err)
23+
}
24+
const refreshToken = user.refreshToken
25+
refresh.requestNewAccessToken('google', refreshToken, function (
26+
_,
27+
accessToken,
28+
refreshToken
29+
) {
30+
user.token = accessToken
31+
user.save().then(user => {
32+
const googleCalendar1 = new gcal.GoogleCalendar(user.token)
33+
34+
googleCalendar1.calendarList.list((err, data) => {
35+
if (err) {
36+
res.json(err)
37+
}
38+
res.json(data)
39+
})
40+
})
41+
})
42+
})
43+
} else {
44+
return res.json(data)
45+
}
46+
})
47+
})
48+
})
49+
50+
// POST
51+
// /calendar/events
52+
// Returns a list of events for a given calendar
53+
router.post('/events', (req, res) => {
54+
const googleId = req.body.googleId
55+
const id = req.body.id
56+
57+
tokenUtils.getToken(googleId).then(token => {
58+
const googleCalendar = new gcal.GoogleCalendar(token)
59+
60+
googleCalendar.events.list(id, function (err, calendarList) {
61+
if (err) {
62+
GoogleUser.findOne({ googleId: googleId }, (err, user) => {
63+
if (err) {
64+
res.json(err)
65+
}
66+
const refreshToken = user.refreshToken
67+
refresh.requestNewAccessToken('google', refreshToken, function (
68+
_,
69+
accessToken,
70+
refreshToken
71+
) {
72+
user.token = accessToken
73+
user.save().then(user => {
74+
const googleCalendar1 = new gcal.GoogleCalendar(user.token)
75+
76+
googleCalendar1.events.list(id, (err, data) => {
77+
if (err) {
78+
res.json(err)
79+
} else {
80+
res.json(data)
81+
console.log(data)
82+
}
83+
})
84+
})
85+
})
86+
})
87+
} else {
88+
return res.json(calendarList)
89+
}
90+
})
91+
})
92+
})
93+
94+
// POST
95+
// /calendar/newevent
96+
// Creates a new event for the calendar id passed in
97+
router.post('/newevent', (req, res) => {
98+
const googleId = req.body.googleId
99+
100+
const id = req.body.id
101+
const start = req.body.startDate
102+
const end = req.body.endDate
103+
const title = req.body.title
104+
const params = {
105+
start: { dateTime: start },
106+
end: { dateTime: end },
107+
summary: title
108+
}
109+
110+
tokenUtils.getToken(googleId).then(token => {
111+
const googleCalendar = new gcal.GoogleCalendar(token)
112+
googleCalendar.events.insert(id, params, function (err, data) {
113+
if (err) {
114+
GoogleUser.findOne({ googleId: googleId }, (err, user) => {
115+
if (err) {
116+
res.json(err)
117+
}
118+
const refreshToken = user.refreshToken
119+
refresh.requestNewAccessToken('google', refreshToken, function (
120+
_,
121+
accessToken,
122+
refreshToken
123+
) {
124+
user.token = accessToken
125+
user.save().then(user => {
126+
const googleCalendar1 = new gcal.GoogleCalendar(user.token)
127+
128+
googleCalendar1.events.insert(id, params, (err, data) => {
129+
if (err) res.json(err)
130+
res.json(data)
131+
})
132+
})
133+
})
134+
})
135+
} else {
136+
return res.json(data)
137+
}
138+
})
139+
})
140+
})
141+
142+
module.exports = router

app/routes/oauth.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const express = require('express')
2+
const router = express.Router()
3+
const passport = require('passport')
4+
5+
// GET
6+
// /oauth/google
7+
router.get(
8+
'/google',
9+
passport.authenticate('google', {
10+
scope: [
11+
'https://www.googleapis.com/auth/plus.login',
12+
'https://www.googleapis.com/auth/calendar'
13+
],
14+
prompt: 'consent',
15+
accessType: 'offline'
16+
})
17+
)
18+
19+
// GET
20+
// /oauth/callback
21+
// Callback url MUST BE similar to one mentioned in the
22+
router.get(
23+
'/google/callback',
24+
passport.authenticate('google', { failureRedirect: '/oauth/google' }),
25+
function (req, res) {
26+
const googleId = req.user.googleId
27+
res.redirect('http://localhost:3000/calendar?googleId=' + googleId)
28+
}
29+
)
30+
31+
module.exports = router

app/utils/token-utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const GoogleUser = require('../models/GoogleUser')
2+
3+
module.exports = {
4+
getToken: async googleId => {
5+
const user = await GoogleUser.findOne({ googleId: googleId })
6+
if (user) {
7+
return user.token
8+
}
9+
}
10+
}

config/passport.js

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,48 @@
1-
// TODO:
2-
// YET TO IMPLEMENT WITH PASSPORT
1+
const GoogleStrategy = require('passport-google-oauth20').Strategy
2+
const GoogleUser = require('../app/models/GoogleUser')
3+
const passport = require('passport')
4+
const refresh = require('passport-oauth2-refresh')
5+
6+
// Google
7+
passport.serializeUser(function (user, done) {
8+
done(null, user.id)
9+
})
10+
11+
passport.deserializeUser(function (id, done) {
12+
GoogleUser.findById(id).then(user => {
13+
done(null, user)
14+
})
15+
})
16+
17+
const strategy = new GoogleStrategy(
18+
{
19+
clientID: process.env.GOOGLE_CLIENT_ID,
20+
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
21+
callbackURL: 'http://localhost:8000/oauth/google/callback'
22+
},
23+
(accessToken, refreshToken, profile, done) => {
24+
GoogleUser.findOneAndUpdate(
25+
{ googleId: profile.id },
26+
{ token: accessToken, refreshToken: refreshToken },
27+
{ new: true, upsert: true }
28+
).then(currentUser => {
29+
if (currentUser) {
30+
done(null, currentUser)
31+
} else {
32+
new GoogleUser({
33+
username: profile.displayName,
34+
googleId: profile.id,
35+
token: accessToken,
36+
refreshToken: refreshToken
37+
})
38+
.save()
39+
.then(newUser => {
40+
done(null, newUser)
41+
})
42+
}
43+
})
44+
}
45+
)
46+
47+
passport.use(strategy)
48+
refresh.use(strategy)

package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,21 @@
1212
"bcrypt": "^3.0.6",
1313
"body-parser": "^1.19.0",
1414
"cookie-parser": "~1.4.4",
15+
"cors": "^2.8.5",
1516
"crypto": "^1.0.1",
1617
"debug": "~2.6.9",
1718
"dotenv": "^8.2.0",
1819
"ejs": "~2.6.1",
1920
"express": "^4.16.4",
21+
"express-session": "^1.17.0",
22+
"google-calendar": "^1.3.2",
2023
"jsonwebtoken": "^8.5.1",
2124
"mongoose": "^5.7.7",
2225
"morgan": "^1.9.1",
26+
"passport": "^0.4.1",
27+
"passport-google-oauth": "^2.0.0",
28+
"passport-google-oauth20": "^2.0.0",
29+
"passport-oauth2-refresh": "^1.1.0",
2330
"validator": "^10.11.0"
2431
},
2532
"jest": {

0 commit comments

Comments
 (0)