-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
executable file
·389 lines (348 loc) · 12.1 KB
/
Copy pathserver.js
File metadata and controls
executable file
·389 lines (348 loc) · 12.1 KB
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
var express = require('express');
var anyDB = require('any-db');
var bodyParser = require("body-parser");
var conn = anyDB.createConnection('sqlite3://Senior-Leaves.db');
var app = express();
var mustache = require('mustache-express');
var moment = require('moment');
var server = require('http').createServer(app);
var io = require('socket.io')(server);
app.engine('html', mustache());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static('views'));
conn.query("CREATE TABLE IF NOT EXISTS leave_records (uid INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, sign_out SMALLDATETIME, sign_in SMALLDATETIME);");
conn.query("CREATE TABLE IF NOT EXISTS student_info (uid INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password TEXT, username TEXT, ban_until SMALLDATETIME);");
conn.query("CREATE TABLE IF NOT EXISTS login (uid INTEGER PRIMARY KEY AUTOINCREMENT, password TEXT);");
conn.query("CREATE TABLE IF NOT EXISTS numLeaves (uid INTEGER PRIMARY KEY AUTOINCREMENT, leaves INTEGER);");
// CLEAR DB
conn.query('DELETE FROM leave_records;');
conn.query('DELETE FROM student_info;');
conn.query('DELETE FROM numLeaves;');
conn.query('DELETE FROM login;');
// set number of leaves = 3
conn.query('INSERT INTO numLeaves (leaves) VALUES (3);', function(err, res) { if (err) throw err; });
// set admin password = "admin"
conn.query('INSERT INTO login (password) VALUES ("admin");');
// sign out for a leave under a specific name
function signout(name, socket) {
// get ban info
getStudentInfo(name, function(result){
if (result.rows.length > 0) {
var student = result.rows[0];
// if user banned
if (checkBanned(student.ban_until)) {
socket.emit('banned');
}
else {
// if not banned but ban date exists, make null
if (student.ban_until != null) {
conn.query('UPDATE student_info SET ban_until = NULL WHERE name = ?;', [name], function(err, result) {
if (err) throw err;
});
}
checkLeaveAvailable(name, function(available) {
// if student has leave available
if (available) {
// add new leave record
conn.query('INSERT INTO leave_records (name, sign_out) VALUES (?, ?);', [name, moment().format('YYYY-MM-DD HH:mm:ss')], function(err, result) {
if (err) throw err;
});
}
// broadcast to listeners
socket.broadcast.emit('new sign out', {
name: name,
signout_time: moment().format('h:mm:ss A M/D/YYYY')
});
socket.emit('refresh');
});
}
}
});
}
// sign in for a leave under a specific name
function signin(name, socket) {
// get the most recent leave record under this name
conn.query('SELECT * FROM leave_records WHERE name = ? ORDER BY uid DESC LIMIT 1;', [name], function(err, result) {
if (err) throw err;
if (result.rows.length > 0) {
var last = result.rows[0];
// if not already signed in
if (last.sign_in == null) {
// update to reflect sign in
conn.query('UPDATE leave_records SET sign_in = ? WHERE uid = ?;', [moment().format('YYYY-MM-DD HH:mm:ss'), last.uid], function(err, result) {
if (err) throw err;
// broadcast to listeners
socket.broadcast.emit('new sign in', {
name: name,
signin_time: moment().format('h:mm:ss A M/D/YYYY')
});
socket.emit('refresh');
});
}
}
});
}
//get date that a student is banned until
function getStudentInfo(name, callback){
conn.query('SELECT * FROM student_info WHERE name = ? LIMIT 1;', [name], function(err, result){
if (err) throw err;
callback(result);
});
}
//check if ban_until date has been reached
function checkBanned(ban_until) {
return ban_until != null && moment().isBefore(moment(ban_until));
}
//check if a non-banned student has leaves this week (true false)
function checkLeaveAvailable(name, callback) {
getCurrentLeaveLimit(function(leaveLimit) {
getLeavesFromThisWeek(name, function(rows) {
callback(rows.length < leaveLimit);
});
});
}
// get the current amount of leaves for this week (probably db call)
function getCurrentLeaveLimit(callback) {
conn.query("SELECT * FROM numLeaves", function(err,data){
if (err) throw err;
var leave_limit = data.rows[0].leaves;
callback(leave_limit);
});
}
// get the records of leaves of a student this week
function getLeavesFromThisWeek(name, callback) {
conn.query('SELECT * FROM leave_records WHERE name = ? AND sign_out > ?;', [name, moment().startOf('week').format("YYYY-MM-DD HH:mm:ss")], function(err, result) {
if (err) throw err;
callback(result.rows);
});
}
//get how many leaves a student has left this week
function getLeavesLeft(name, callback){
getCurrentLeaveLimit(function(leave_limit){
getLeavesFromThisWeek(name, function(leaves_taken){
callback(leave_limit - leaves_taken.length);
});
});
}
//render the student pg
function renderStudPg(response, name, username){
var student = {};
student.name = name;
student.username = username;
getStudentInfo(name, function(banDate){
if (banDate.rows.length == 0){ //if user does not exist, render the thome page with an error message
student.error = true;
response.render('homepage.html', student);
}
else{ //user does exist, so keep going
banDate = banDate.rows[0].ban_until
getLeavesFromThisWeek(name, function(leaves_taken){
if (leaves_taken.length == 0) { //if this user has not taken any leves yet
student.last_leave = "No leaves have been taken yet!"
}
else{ //else this user has taken a leave, and so set the last_leave property equal to the date of the last time he/she signed out.
student.last_leave = leaves_taken[leaves_taken.length - 1].sign_out;
}
if(checkBanned(banDate) == true){ //if user is banned, don't show a button, just show banned until + the date
student.message = "Banned until:" + banDate;
student.num_leaves = "Banned";
student.title = "Banned";
response.render('student.html', student);
}
else{ //if user isn't banned
getLeavesLeft(name, function(leaves_left){
student.num_leaves = leaves_left;
if (leaves_taken.length == 0){ //user has never taken a leave before
student.sign_out = true;
student.title = "Sign Out"
}
else if(leaves_taken[leaves_taken.length -1].sign_in == null){ //if the user has not signed back in
student.sign_in = true;
student.title = "Sign In";
}
else if (leaves_left == 0){ //if the user has no leaves left this week
student.message = "Wait until next week";
student.title = "Wait"
}
else if (moment(student.last_leave).isSame(moment(), 'day')){ //if they have taken a leave already today
student.message = "Wait until tomorrow";
student.title = "Wait"
}
else{
student.sign_out = true;
student.title = "Sign Out"
}
response.render('student.html', student);
});
}
});
}
});
}
// check admin password and render page if legitimate
function authenticateAdmin(response, userPassword){
conn.query("SELECT * FROM login", function(err, data){
if (err) throw err;
if (data.rows.length > 0) {
if (data.rows[0].password == userPassword){
renderAdminPage(response);
}
else{
response.redirect('/login');
}
}
});
}
// initialize a new student account in db
function createNewAccount(request, response){
var name = request.body.name;
var username = request.body.username;
var password = request.body.password;
var confirmPassword = request.body.confirmPassword;
var errorObj = {};
getStudentInfo(name, function(student){
if (student.rows.length == 0){
errorObj.errorMessage = "User " + name + " is not in the database. Please contact a creator of this page, if there is a mistake."
errorObj.nameError = true;
response.render('newAccount.html', errorObj);
}
else if (password != confirmPassword){
errorObj.errorMessage = "The passwords do not match.";
errorObj.passwordError = true;
response.render('newAccount.html', errorObj);
}
else if (name == "" || username == "" || password == ""|| confirmPassword == ""){
errorObj.errorMessage = "Please fill out all required fields.";
errorObj.emptyError = true;
response.render('newAccount.html', errorObj);
}
else{
conn.query("UPDATE student_info SET username = ?, password = ? WHERE name = ?", [username, password, name], function(err, data){ if (err) throw err; });
response.redirect('/');
}
});
}
// check student password
function authenticateStudent(request, response){
username = request.body.username;
password = request.body.password;
conn.query('SELECT * FROM student_info', function(err, students){
if (err) throw err;
for (var i = 0; i<students.rows.length; i++){
if (username == students.rows[i].username && password == students.rows[i].password){
renderStudPg(response, students.rows[i].name, students.rows[i].username);
break;
}
else if (i == students.rows.length - 1){
response.render('homepage.html', {wrong: true});
break;
}
}
});
}
// check if a date is valid
function checkLegalDate(date) {
var day = parseInt(date.day);
var year = parseInt(date.year);
return (day > 0 && day <= 31) && year > 0;
}
// display admin page
function renderAdminPage(res) {
var renderObject = {
rows: [],
students: []
};
// get currently out leaves
conn.query('SELECT * FROM leave_records WHERE sign_in IS NULL;', function(err, result) {
if (err) throw err;
for (var i = 0; i < result.rows.length; i++) {
var row = result.rows[i];
renderObject.rows.push({
name: row.name,
id: row.name.split(' ').join(''),
signout_time: row.sign_out
});
}
// get all students
conn.query('SELECT * FROM student_info;', function(err, result) {
if (err) throw err;
for (var i = 0; i < result.rows.length; i++) {
var row = result.rows[i];
renderObject.students.push({
name: row.name,
student_id: row.name.split(' ').join(''),
ban_until: row.ban_until != null ? moment(row.ban_until).format('MMMM DD, YYYY') : ''
});
}
res.render('admin.html', renderObject);
});
});
}
// add senior info to database on server start
function addStudentsToDB() {
// in reality this would read names in from a file and enter them in the DB
// debug test data:
conn.query('INSERT INTO student_info (name) VALUES ("Thomas Castleman"), ("Stewart Morris"), ("Yuelin Dang"), ("Emmett Barger");');
console.log("Successfully added student data to db");
}
// socket handling
io.on('connection', function(socket) {
// on request to sign out
socket.on('signout', function(data) {
signout(data.name, socket);
});
// on request to sign in
socket.on('signin', function(data) {
signin(data.name, socket);
});
// on request to make ban
socket.on('ban', function(data) {
var date = data.date;
var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'Novemeber', 'December'];
// if date is safe
if (checkLegalDate(data.date)) {
var date = moment(date.year + '-' + (months.indexOf(date.month) + 1) + '-' + date.day, 'YYYY-MM-DD');
socket.emit('update ban date', {
name: data.name,
date: date.format('MMMM DD, YYYY')
});
// update ban date
conn.query('UPDATE student_info SET ban_until = ? WHERE name = ?;', [date.format('YYYY-MM-DD'), data.name], function(err, result) {
if (err) throw err;
});
}
});
});
// ROUTES:
app.get("/", function(request, response){
response.render('homepage.html');
});
app.get("/login", function(request, response){
response.render('login.html');
});
app.post("/student", function(request, response){
authenticateStudent(request, response);
});
app.get('/student', function(req, res) {
res.redirect('/');
})
app.get('/admin', function(request, response){
response.redirect('/login');
});
app.post("/admin", function(request, response){
authenticateAdmin(response, request.body.password);
});
app.get('/newAccount', function(request, response){
response.render('newAccount.html');
});
app.post('/newAccount', function(request, response){
createNewAccount(request, response);
});
// catch all unknown endpoints and redirect
app.get('*', function(req, res) {
res.redirect('/');
})
server.listen(8080, function() {
console.log("Senior leaves server listening on port 8080");
addStudentsToDB();
});