-
Notifications
You must be signed in to change notification settings - Fork 11
/
server.js
215 lines (183 loc) · 5.99 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
'use strict';
const express = require('express');
const morgan = require('morgan'); // logging middleware
const {check, validationResult} = require('express-validator'); // validation middleware
const examDao = require('./exam-dao'); // module for accessing the exams in the DB
const passport = require('passport'); // auth middleware
const LocalStrategy = require('passport-local').Strategy; // username and password for login
const session = require('express-session'); // enable sessions
const userDao = require('./user-dao'); // module for accessing the users in the DB
/*** Set up Passport ***/
// set up the "username and password" login strategy
// by setting a function to verify username and password
passport.use(new LocalStrategy(
function(username, password, done) {
userDao.getUser(username, password).then((user) => {
if (!user)
return done(null, false, { message: 'Incorrect username and/or password.' });
return done(null, user);
})
}
));
// serialize and de-serialize the user (user object <-> session)
// we serialize the user id and we store it in the session: the session is very small in this way
passport.serializeUser((user, done) => {
done(null, user.id);
});
// starting from the data in the session, we extract the current (logged-in) user
passport.deserializeUser((id, done) => {
userDao.getUserById(id)
.then(user => {
done(null, user); // this will be available in req.user
}).catch(err => {
done(err, null);
});
});
// init express
const app = express();
const port = 3001;
// set-up the middlewares
app.use(morgan('dev'));
app.use(express.json());
// custom middleware: check if a given request is coming from an authenticated user
const isLoggedIn = (req, res, next) => {
if(req.isAuthenticated())
return next();
return res.status(401).json({ error: 'not authenticated'});
}
// set up the session
app.use(session({
// by default, Passport uses a MemoryStore to keep track of the sessions
secret: 'a secret sentence not to share with anybody and anywhere, used to sign the session ID cookie',
resave: false,
saveUninitialized: false
}));
// then, init passport
app.use(passport.initialize());
app.use(passport.session());
/*** Courses/Exams APIs ***/
// GET /api/courses
app.get('/api/courses', (req, res) => {
examDao.listCourses()
.then(courses => res.json(courses))
.catch(() => res.status(500).end());
});
// GET /api/courses/<code>
app.get('/api/courses/:code', async (req, res) => {
try {
const result = await examDao.getCourse(req.params.code);
if(result.error)
res.status(404).json(result);
else
res.json(result);
} catch(err) {
res.status(500).end();
}
});
// GET /api/exams
app.get('/api/exams', isLoggedIn, async (req, res) => {
try {
const exams = await examDao.listExams(req.user.id);
res.json(exams);
} catch(err) {
res.status(500).end();
}
});
// POST /api/exams
app.post('/api/exams', isLoggedIn, [
check('score').isInt({min: 18, max: 31}),
check('code').isLength({min: 7, max: 7}),
check('date').isDate({format: 'YYYY-MM-DD', strictMode: true})
], async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({errors: errors.array()});
}
const exam = {
code: req.body.code,
score: req.body.score,
date: req.body.date,
};
try {
await examDao.createExam(exam, req.user.id);
res.status(201).end();
} catch(err) {
res.status(503).json({error: `Database error during the creation of exam ${exam.code}.`});
}
});
// PUT /api/exams/<code>
app.put('/api/exams/:code', isLoggedIn, [
check('score').isInt({min: 18, max: 31}),
check('code').isLength({min: 7, max: 7}),
check('date').isDate({format: 'YYYY-MM-DD', strictMode: true})
], async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({errors: errors.array()});
}
const exam = req.body;
// you can also check here if the code passed in the URL matches with the code in req.body
try {
await examDao.updateExam(exam, req.user.id);
res.status(200).end();
} catch(err) {
res.status(503).json({error: `Database error during the update of exam ${req.params.code}.`});
}
});
// DELETE /api/exams/<code>
app.delete('/api/exams/:code', isLoggedIn, async (req, res) => {
try {
await examDao.deleteExam(req.params.code, req.user.id);
res.status(204).end();
} catch(err) {
res.status(503).json({ error: `Database error during the deletion of exam ${req.params.code}.`});
}
});
/*** Users APIs ***/
// POST /sessions
// login
app.post('/api/sessions', function(req, res, next) {
passport.authenticate('local', (err, user, info) => {
if (err)
return next(err);
if (!user) {
// display wrong login messages
return res.status(401).json(info);
}
// success, perform the login
req.login(user, (err) => {
if (err)
return next(err);
// req.user contains the authenticated user, we send all the user info back
// this is coming from userDao.getUser()
return res.json(req.user);
});
})(req, res, next);
});
// ALTERNATIVE: if we are not interested in sending error messages...
/*
app.post('/api/sessions', passport.authenticate('local'), (req,res) => {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.json(req.user);
});
*/
// DELETE /sessions/current
// logout
app.delete('/api/sessions/current', (req, res) => {
req.logout();
res.end();
});
// GET /sessions/current
// check whether the user is logged in or not
app.get('/api/sessions/current', (req, res) => {
if(req.isAuthenticated()) {
res.status(200).json(req.user);}
else
res.status(401).json({error: 'Unauthenticated user!'});;
});
/*** Other express-related instructions ***/
// Activate the server
app.listen(port, () => {
console.log(`react-score-server listening at http://localhost:${port}`);
});