Merge branch 'user-accounts' into 'develop'
Add user account functionality See merge request sudoer777/cvcs-score-tracker!8main
commit
2c747fc6fa
30
app.js
30
app.js
|
@ -3,14 +3,42 @@ var express = require('express');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var cookieParser = require('cookie-parser');
|
var cookieParser = require('cookie-parser');
|
||||||
var logger = require('morgan');
|
var logger = require('morgan');
|
||||||
|
var random = require('./database/accounts/random');
|
||||||
|
const passport = require('passport');
|
||||||
|
const session = require('express-session');
|
||||||
|
const accounts = require('./database/accounts/accounts');
|
||||||
|
var flash = require('connect-flash');
|
||||||
|
|
||||||
|
|
||||||
var indexRouter = require('./routes/index');
|
var indexRouter = require('./routes/index');
|
||||||
var usersRouter = require('./routes/users');
|
var usersRouter = require('./routes/users');
|
||||||
var dataRouter = require('./routes/data');
|
var dataRouter = require('./routes/data');
|
||||||
var manageRouter = require('./routes/manage');
|
var manageRouter = require('./routes/manage');
|
||||||
|
var authRouter = require('./routes/auth');
|
||||||
|
var adminRouter = require('./routes/admin');
|
||||||
|
|
||||||
var app = express();
|
var app = express();
|
||||||
|
|
||||||
|
// flash setup
|
||||||
|
app.use(flash());
|
||||||
|
|
||||||
|
// session setup
|
||||||
|
app.use(
|
||||||
|
session({
|
||||||
|
secret: random.makeid(20),
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// passport setup
|
||||||
|
app.use(passport.initialize());
|
||||||
|
app.use(passport.session());
|
||||||
|
|
||||||
|
//passport.use(accounts.createStrategy());
|
||||||
|
//passport.serializeUser(accounts.serializeUser());
|
||||||
|
//passport.deserializeUser(accounts.deserializeUser());
|
||||||
|
|
||||||
// view engine setup
|
// view engine setup
|
||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
app.set('view engine', 'pug');
|
app.set('view engine', 'pug');
|
||||||
|
@ -25,6 +53,8 @@ app.use('/', indexRouter);
|
||||||
app.use('/users', usersRouter);
|
app.use('/users', usersRouter);
|
||||||
app.use('/data', dataRouter);
|
app.use('/data', dataRouter);
|
||||||
app.use('/manage', manageRouter);
|
app.use('/manage', manageRouter);
|
||||||
|
app.use('/auth', authRouter);
|
||||||
|
app.use('/admin', adminRouter);
|
||||||
|
|
||||||
|
|
||||||
// catch 404 and forward to error handler
|
// catch 404 and forward to error handler
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
const database = require('./../database');
|
||||||
|
const passport = require('passport');
|
||||||
|
const localStrategy = require('passport-local').Strategy;
|
||||||
|
const bcrypt = require('bcrypt');
|
||||||
|
|
||||||
|
class User {
|
||||||
|
constructor(id, email, isAdmin) {
|
||||||
|
this.id = id;
|
||||||
|
this.email = email;
|
||||||
|
this.isAdmin = isAdmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function checkForAdminAccount() {
|
||||||
|
|
||||||
|
const adminUsersQuery = `SELECT *
|
||||||
|
FROM accounts.users
|
||||||
|
WHERE admin = true;`;
|
||||||
|
const adminUsers = await database.executeQuery(adminUsersQuery);
|
||||||
|
|
||||||
|
if(adminUsers.length == 0) {
|
||||||
|
const passwordHash = await generateHash('admin');
|
||||||
|
const createTempAdminQuery = `INSERT INTO accounts.users(email, password, admin)
|
||||||
|
VALUES('admin@example.com', $1, true);`;
|
||||||
|
database.executeQuery(createTempAdminQuery, [passwordHash]);
|
||||||
|
console.log("Created temp admin account 'admin@example.com' with password 'admin'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkForAdminAccount();
|
||||||
|
|
||||||
|
|
||||||
|
passport.use(new localStrategy({
|
||||||
|
usernameField: 'email',
|
||||||
|
passwordField: 'password'},
|
||||||
|
(username, password, cb) => {
|
||||||
|
query = `SELECT user_id, email, password, admin
|
||||||
|
FROM accounts.users
|
||||||
|
WHERE email = $1`;
|
||||||
|
database.executeQuery(query, [username])
|
||||||
|
.then(result => {
|
||||||
|
if(result.length > 0) {
|
||||||
|
const first = result[0];
|
||||||
|
const matches = bcrypt.compareSync(password, first[2]);
|
||||||
|
if(matches) {
|
||||||
|
return cb(null, { id: first[0], email: first[1], admin: first[3] })
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return cb(null, false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return cb(null, false)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
passport.serializeUser((user, done) => {
|
||||||
|
done(null, user.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
passport.deserializeUser((id, cb) => {
|
||||||
|
query = `SELECT user_id, email, admin
|
||||||
|
FROM accounts.users
|
||||||
|
WHERE user_id = $1`;
|
||||||
|
database.executeQuery(query, [parseInt(id, 10)])
|
||||||
|
.then(result => {
|
||||||
|
cb(null, result[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
async function generateHash(password) {
|
||||||
|
const salt = bcrypt.genSaltSync();
|
||||||
|
return bcrypt.hashSync(password, salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function create(email, password, isAdmin) {
|
||||||
|
const hash = await generateHash(password);
|
||||||
|
|
||||||
|
const query = `INSERT INTO accounts.users(email, password, admin)
|
||||||
|
VALUES($1, $2, $3)`;
|
||||||
|
await database.executeQuery(query, [email, hash, isAdmin]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function edit(id, email, password, isAdmin) {
|
||||||
|
if(password) {
|
||||||
|
const hash = await generateHash(password);
|
||||||
|
|
||||||
|
const query = `UPDATE accounts.users
|
||||||
|
SET email = $2,
|
||||||
|
password = $3,
|
||||||
|
admin = $4
|
||||||
|
WHERE user_id = $1;`;
|
||||||
|
await database.executeQuery(query, [id, email, hash, isAdmin]);
|
||||||
|
} else {
|
||||||
|
const query = `UPDATE accounts.users
|
||||||
|
SET email = $2,
|
||||||
|
admin = $3
|
||||||
|
WHERE user_id = $1;`;
|
||||||
|
await database.executeQuery(query, [id, email, isAdmin]);
|
||||||
|
}
|
||||||
|
return new User(id, email, isAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function remove(id) {
|
||||||
|
const query = `DELETE FROM accounts.users
|
||||||
|
WHERE user_id = $1
|
||||||
|
RETURNING email, admin;`;
|
||||||
|
const row = (await database.executeQuery(query, [id]))[0];
|
||||||
|
return new User(id, row[0], row[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrieveAll() {
|
||||||
|
const query = `SELECT user_id, email, admin
|
||||||
|
FROM accounts.users
|
||||||
|
ORDER BY email;`
|
||||||
|
const table = await database.executeQuery(query);
|
||||||
|
|
||||||
|
const accountsList = [];
|
||||||
|
table.forEach((row) => {
|
||||||
|
accountsList.push(new User(row[0], row[1], row[2]));
|
||||||
|
});
|
||||||
|
return accountsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFromID(id) {
|
||||||
|
const query = `SELECT user_id, email, admin
|
||||||
|
FROM accounts.users
|
||||||
|
WHERE user_id = $1;`;
|
||||||
|
const row = (await database.executeQuery(query, [id]))[0];
|
||||||
|
|
||||||
|
return new User(id, row[1], row[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.create = create;
|
||||||
|
exports.edit = edit;
|
||||||
|
exports.remove = remove;
|
||||||
|
exports.retrieveAll = retrieveAll;
|
||||||
|
exports.getFromID = getFromID;
|
||||||
|
exports.passport = passport;
|
|
@ -0,0 +1,12 @@
|
||||||
|
function makeid(length) {
|
||||||
|
var result = '';
|
||||||
|
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
var charactersLength = characters.length;
|
||||||
|
for ( var i = 0; i < length; i++ ) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() *
|
||||||
|
charactersLength));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.makeid = makeid;
|
|
@ -26,16 +26,14 @@ async function Initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function checkForDatabaseInitialization() {
|
async function checkForDatabaseInitialization() {
|
||||||
const query = `SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'scores'`;
|
const scoresSchemaExistsQuery = `SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'scores'`;
|
||||||
let result = await executeQuery(query);
|
let result = await executeQuery(scoresSchemaExistsQuery);
|
||||||
|
|
||||||
const scoresSchemaExists = result.length !== 0;
|
const scoresSchemaExists = result.length !== 0;
|
||||||
|
|
||||||
if(!scoresSchemaExists) {
|
if(!scoresSchemaExists) {
|
||||||
Initialize();
|
await Initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkForDatabaseInitialization();
|
checkForDatabaseInitialization();
|
||||||
|
|
|
@ -22,10 +22,7 @@ scores:
|
||||||
accounts:
|
accounts:
|
||||||
|
|
||||||
users:
|
users:
|
||||||
*user_id* | email | salt | password_hash | role | approved
|
*user_id* | email | password | admin
|
||||||
|
|
||||||
sessions:
|
|
||||||
*session_id* | ~user_id~ | expiration_date
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -33,6 +30,18 @@ accounts:
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE SCHEMA IF NOT EXISTS accounts;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS accounts.users(
|
||||||
|
user_id BIGINT GENERATED ALWAYS AS IDENTITY,
|
||||||
|
email TEXT UNIQUE NOT NULL,
|
||||||
|
password TEXT NOT NULL,
|
||||||
|
admin BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
PRIMARY KEY(user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CREATE SCHEMA IF NOT EXISTS scores;
|
CREATE SCHEMA IF NOT EXISTS scores;
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +90,7 @@ CREATE TABLE IF NOT EXISTS scores.games(
|
||||||
team2_id BIGINT,
|
team2_id BIGINT,
|
||||||
team1_score INTEGER,
|
team1_score INTEGER,
|
||||||
team2_score INTEGER,
|
team2_score INTEGER,
|
||||||
/* submitter_id BIGINT,*/
|
submitter_id BIGINT,
|
||||||
updated_timestamp TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
updated_timestamp TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||||||
PRIMARY KEY(game_id),
|
PRIMARY KEY(game_id),
|
||||||
CONSTRAINT fk_division
|
CONSTRAINT fk_division
|
||||||
|
@ -95,11 +104,10 @@ CREATE TABLE IF NOT EXISTS scores.games(
|
||||||
REFERENCES scores.teams(team_id),
|
REFERENCES scores.teams(team_id),
|
||||||
CONSTRAINT fk_team2
|
CONSTRAINT fk_team2
|
||||||
FOREIGN KEY(team2_id)
|
FOREIGN KEY(team2_id)
|
||||||
REFERENCES scores.teams(team_id)
|
REFERENCES scores.teams(team_id),
|
||||||
/* CONSTRAINT fk_submitter
|
CONSTRAINT fk_submitter
|
||||||
FOREIGN KEY(submitter_id)
|
FOREIGN KEY(submitter_id)
|
||||||
REFERENCES accounts.users(user_id)*/
|
REFERENCES accounts.users(user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
|
@ -5,7 +5,7 @@ const database = require('./../database');
|
||||||
|
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
constructor(id, date, team1ID, team2ID, team1Score, team2Score, divisionID, seasonID) {
|
constructor(id, date, team1ID, team2ID, team1Score, team2Score, divisionID, seasonID, submitterID) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.date = date;
|
this.date = date;
|
||||||
this.team1ID = team1ID;
|
this.team1ID = team1ID;
|
||||||
|
@ -14,17 +14,18 @@ class Game {
|
||||||
this.team2Score = team2Score;
|
this.team2Score = team2Score;
|
||||||
this.divisionID = divisionID;
|
this.divisionID = divisionID;
|
||||||
this.seasonID = seasonID;
|
this.seasonID = seasonID;
|
||||||
|
this.submitterID = submitterID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score) {
|
async function add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, userID) {
|
||||||
const query = `INSERT INTO scores.games(division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score)
|
const query = `INSERT INTO scores.games(division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_id)
|
||||||
VALUES($1, $2, $3, $4, $5, $6, $7)
|
VALUES($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
RETURNING game_id;`;
|
RETURNING game_id;`;
|
||||||
|
|
||||||
const id = (await database.executeQuery(query, [divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score]))[0][0];
|
const id = (await database.executeQuery(query, [divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, userID]))[0][0];
|
||||||
return new Game(id, date, team1ID, team2ID, team1Score, team2Score);
|
return new Game(id, date, team1ID, team2ID, team1Score, team2Score);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +72,20 @@ async function retrieve(teamID, divisionID, seasonID) {
|
||||||
return gamesList;
|
return gamesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function retrieveByUser(userID) {
|
||||||
|
const query = `SELECT game_id, division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score
|
||||||
|
FROM scores.games
|
||||||
|
WHERE submitter_id = $1
|
||||||
|
ORDER BY game_date DESC;`;
|
||||||
|
const table = await database.executeQuery(query, [userID]);
|
||||||
|
|
||||||
|
const gamesList = [];
|
||||||
|
table.forEach((row) => {
|
||||||
|
gamesList.push(new Game(row[0], row[3].toISOString().slice(0,10), row[4], row[5], row[6], row[7], row[1], row[2]));
|
||||||
|
});
|
||||||
|
return gamesList;
|
||||||
|
}
|
||||||
|
|
||||||
async function edit(gameID, divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score) {
|
async function edit(gameID, divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score) {
|
||||||
const query = `UPDATE scores.games
|
const query = `UPDATE scores.games
|
||||||
SET division_id = $2,
|
SET division_id = $2,
|
||||||
|
@ -86,11 +101,11 @@ async function edit(gameID, divisionID, seasonID, date, team1ID, team2ID, team1S
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFromID(gameID) {
|
async function getFromID(gameID) {
|
||||||
const query = `SELECT game_id, division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score
|
const query = `SELECT game_id, division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_id
|
||||||
FROM scores.games
|
FROM scores.games
|
||||||
WHERE game_id = $1;`;
|
WHERE game_id = $1;`;
|
||||||
const row = (await database.executeQuery(query, [gameID]))[0];
|
const row = (await database.executeQuery(query, [gameID]))[0];
|
||||||
return new Game(row[0], row[3].toISOString().slice(0,10), row[4], row[5], row[6], row[7], row[1], row[2]);
|
return new Game(row[0], row[3].toISOString().slice(0,10), row[4], row[5], row[6], row[7], row[1], row[2], row[8]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,5 +115,6 @@ async function getFromID(gameID) {
|
||||||
exports.add = add;
|
exports.add = add;
|
||||||
exports.remove = remove;
|
exports.remove = remove;
|
||||||
exports.retrieve = retrieve;
|
exports.retrieve = retrieve;
|
||||||
|
exports.retrieveByUser = retrieveByUser;
|
||||||
exports.edit = edit;
|
exports.edit = edit;
|
||||||
exports.getFromID = getFromID;
|
exports.getFromID = getFromID;
|
|
@ -69,7 +69,6 @@ async function getFromID(id) {
|
||||||
FROM scores.teams
|
FROM scores.teams
|
||||||
WHERE team_id = $1;`;
|
WHERE team_id = $1;`;
|
||||||
const row = (await database.executeQuery(query, [id]))[0];
|
const row = (await database.executeQuery(query, [id]))[0];
|
||||||
console.log(row);
|
|
||||||
return new Team(id, row[0], row[1]);
|
return new Team(id, row[0], row[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,14 +8,18 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^3.2.2",
|
"async": "^3.2.2",
|
||||||
|
"bcrypt": "^5.0.1",
|
||||||
|
"connect-flash": "^0.1.1",
|
||||||
"cookie-parser": "~1.4.3",
|
"cookie-parser": "~1.4.3",
|
||||||
"debug": "~2.6.9",
|
"debug": "~2.6.9",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"express": "~4.16.0",
|
"express": "~4.16.0",
|
||||||
|
"express-session": "^1.17.2",
|
||||||
"http-errors": "~1.6.2",
|
"http-errors": "~1.6.2",
|
||||||
"morgan": "~1.9.0",
|
"morgan": "~1.9.0",
|
||||||
"nodemailer": "^6.6.5",
|
"nodemailer": "^6.6.5",
|
||||||
"passport": "^0.5.0",
|
"passport": "^0.5.0",
|
||||||
|
"passport-local": "^1.0.0",
|
||||||
"pg": "^8.7.1",
|
"pg": "^8.7.1",
|
||||||
"pug": "2.0.0-beta11"
|
"pug": "2.0.0-beta11"
|
||||||
},
|
},
|
||||||
|
|
|
@ -65,8 +65,27 @@ export async function getGames(teamID = undefined, divisionID = undefined, seaso
|
||||||
return gamesList;
|
return gamesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getGamesByUser() {
|
||||||
|
let URL = '/data/games?user=1';
|
||||||
|
const response = await fetch(URL);
|
||||||
|
const gamesList = await response.json();
|
||||||
|
return gamesList;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getGame(gameID) {
|
export async function getGame(gameID) {
|
||||||
const response = await fetch(`/data/game?game=${gameID}`);
|
const response = await fetch(`/data/game?game=${gameID}`);
|
||||||
const game = await response.json();
|
const game = await response.json();
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAccounts() {
|
||||||
|
const response = await fetch(`/data/accounts`);
|
||||||
|
const accounts = await response.json();
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAccount(accountID) {
|
||||||
|
const response = await fetch(`/data/account?account=${accountID}`);
|
||||||
|
const account = await response.json();
|
||||||
|
return account;
|
||||||
|
}
|
|
@ -177,11 +177,14 @@ genderDropdown.onchange = listDivisions;
|
||||||
teamDropdown.onchange = listGames;
|
teamDropdown.onchange = listGames;
|
||||||
seasonDropdown.onchange = listGames;
|
seasonDropdown.onchange = listGames;
|
||||||
|
|
||||||
|
if(addScoreButton) {
|
||||||
|
addScoreButton.addEventListener('click', () => {
|
||||||
|
window.location.href = '/manage/game';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addScoreButton.addEventListener('click', () => {
|
if(manageButton) {
|
||||||
window.location.href = '/manage/game';
|
manageButton.addEventListener('click', () => {
|
||||||
});
|
window.location.href = '/manage'
|
||||||
|
});
|
||||||
manageButton.addEventListener('click', () => {
|
}
|
||||||
window.location.href = '/manage'
|
|
||||||
});
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
const logInButton = document.getElementById('login-button');
|
||||||
|
const logOutButton = document.getElementById('logout-button');
|
||||||
|
const homeButton = document.getElementById('home-button');
|
||||||
|
|
||||||
|
if(logInButton) {
|
||||||
|
logInButton.addEventListener('click', () => {
|
||||||
|
window.location.href = "/auth/login";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(logOutButton) {
|
||||||
|
logOutButton.addEventListener('click', () => {
|
||||||
|
window.location.href = "/auth/logout";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(homeButton) {
|
||||||
|
homeButton.addEventListener('click', () => {
|
||||||
|
window.location.href = '/';
|
||||||
|
});
|
||||||
|
}
|
|
@ -294,6 +294,49 @@ CATEGORIES.push(new Category(
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
CATEGORIES.push(new Category(
|
||||||
|
"accounts",
|
||||||
|
async function getAccounts() {
|
||||||
|
return await Data.getAccounts();
|
||||||
|
},
|
||||||
|
async function listAccountHeaders() {
|
||||||
|
const headerRow = document.createElement('tr');
|
||||||
|
|
||||||
|
const emailHeader = document.createElement('th');
|
||||||
|
emailHeader.textContent = "Email";
|
||||||
|
headerRow.appendChild(emailHeader);
|
||||||
|
|
||||||
|
const spacerHeader = document.createElement('th');
|
||||||
|
spacerHeader.classList.add('spacer-column');
|
||||||
|
headerRow.appendChild(spacerHeader);
|
||||||
|
|
||||||
|
const adminHeader = document.createElement('th');
|
||||||
|
adminHeader.textContent = "Admin?";
|
||||||
|
headerRow.appendChild(adminHeader);
|
||||||
|
|
||||||
|
itemsListTable.appendChild(headerRow);
|
||||||
|
},
|
||||||
|
function listAccount(account, row) {
|
||||||
|
const emailCell = document.createElement('td');
|
||||||
|
emailCell.textContent = account.email;
|
||||||
|
row.appendChild(emailCell);
|
||||||
|
|
||||||
|
const spacerCell = document.createElement('td');
|
||||||
|
row.appendChild(spacerCell);
|
||||||
|
|
||||||
|
const adminCell = document.createElement('td');
|
||||||
|
adminCell.textContent = account.isAdmin;
|
||||||
|
row.appendChild(adminCell);
|
||||||
|
},
|
||||||
|
async function addAccount() {
|
||||||
|
window.location.href = "/manage/account";
|
||||||
|
},
|
||||||
|
async function editAccount(id) {
|
||||||
|
window.location.href = `/manage/account?account=${id}`;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function listItems(category) {
|
async function listItems(category) {
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import * as Data from "../data.js";
|
||||||
|
import * as Form from "../form.js";
|
||||||
|
|
||||||
|
const submissionForm = document.getElementById('submission-form');
|
||||||
|
const emailTextbox = document.getElementById('email-textbox');
|
||||||
|
const passwordTextbox = document.getElementById('password-textbox');
|
||||||
|
const adminCheckboxSection = document.getElementById('admin-checkbox-section');
|
||||||
|
const adminCheckbox = document.getElementById('admin-checkbox');
|
||||||
|
const submitButton = document.getElementById('submit-button');
|
||||||
|
const deleteButton = document.getElementById('delete-button');
|
||||||
|
|
||||||
|
async function Initialize() {
|
||||||
|
let params = new URLSearchParams(location.search);
|
||||||
|
let accountID = params.get('account') || (document.getElementById('account-id') ? document.getElementById('account-id').value : null);
|
||||||
|
if(accountID) {
|
||||||
|
const account = await Data.getAccount(accountID);
|
||||||
|
console.log(account);
|
||||||
|
|
||||||
|
emailTextbox.value = account.email;
|
||||||
|
|
||||||
|
passwordTextbox.placeholder = "leave unchanged";
|
||||||
|
|
||||||
|
adminCheckbox.checked = account.isAdmin;
|
||||||
|
|
||||||
|
if(!document.getElementById('account-id')) {
|
||||||
|
adminCheckboxSection.style.visibility = "visible";
|
||||||
|
adminCheckbox.disabled = false;
|
||||||
|
|
||||||
|
Form.addHiddenValue('account', accountID, submissionForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteButton.style.visibility = "visible";
|
||||||
|
deleteButton.disabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
adminCheckboxSection.style.visibility = "visible";
|
||||||
|
adminCheckbox.disabled = false;
|
||||||
|
}
|
||||||
|
emailTextbox.disabled = false;
|
||||||
|
emailTextbox.addEventListener('keyup', checkDataValidity);
|
||||||
|
passwordTextbox.disabled = false;
|
||||||
|
passwordTextbox.addEventListener('keyup', checkDataValidity);
|
||||||
|
checkDataValidity();
|
||||||
|
}
|
||||||
|
Initialize();
|
||||||
|
|
||||||
|
async function checkDataValidity() {
|
||||||
|
let dataIsValid = true;
|
||||||
|
|
||||||
|
if(!passwordTextbox.value && !passwordTextbox.placeholder) dataIsValid = false;
|
||||||
|
if(!emailTextbox.value) dataIsValid = false;
|
||||||
|
|
||||||
|
if(dataIsValid) submitButton.disabled = false;
|
||||||
|
else submitButton.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Form.addRemoveFunction(deleteButton, submissionForm, "account");
|
|
@ -25,6 +25,8 @@ async function initializeForm() {
|
||||||
|
|
||||||
const game = await Data.getGame(gameID);
|
const game = await Data.getGame(gameID);
|
||||||
|
|
||||||
|
Form.addHiddenValue('game', gameID, submissionForm);
|
||||||
|
|
||||||
Form.populateSeasons(seasonDropdown, game.seasonID);
|
Form.populateSeasons(seasonDropdown, game.seasonID);
|
||||||
Data.getDivision(game.divisionID)
|
Data.getDivision(game.divisionID)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
@ -65,6 +67,19 @@ async function initializeForm() {
|
||||||
team1ScoreTextbox.disabled = false;
|
team1ScoreTextbox.disabled = false;
|
||||||
team2ScoreTextbox.disabled = false;
|
team2ScoreTextbox.disabled = false;
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
|
|
||||||
|
sportDropdown.onchange = () => {
|
||||||
|
Form.populateGenders(genderDropdown, sportDropdown.value)
|
||||||
|
.then(() => {
|
||||||
|
Form.populateDivisions(divisionDropdown, sportDropdown.value, genderDropdown.value);
|
||||||
|
});
|
||||||
|
Form.populateTeams(team1Dropdown, sportDropdown.value);
|
||||||
|
Form.populateTeams(team2Dropdown, sportDropdown.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
genderDropdown.onchange = () => {
|
||||||
|
Form.populateDivisions(divisionDropdown, sportDropdown.value, genderDropdown.value);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
initializeForm();
|
initializeForm();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
import * as Data from "./../data.js";
|
||||||
|
|
||||||
|
const gamesListTable = document.getElementById('games-list');
|
||||||
|
const addNewButton = document.getElementById('add-new-button');
|
||||||
|
const manageAccountButton = document.getElementById('manage-account-button');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function getGenderLetter(genderName) {
|
||||||
|
return genderName == "female" ? "F" : "M";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listGameHeaders() {
|
||||||
|
const headerRow = document.createElement('tr');
|
||||||
|
|
||||||
|
const teamsHeader = document.createElement('th');
|
||||||
|
teamsHeader.textContent = "Teams";
|
||||||
|
headerRow.appendChild(teamsHeader);
|
||||||
|
|
||||||
|
const scoreHeader = document.createElement('th');
|
||||||
|
headerRow.appendChild(scoreHeader);
|
||||||
|
|
||||||
|
const spacerHeader = document.createElement('th');
|
||||||
|
spacerHeader.classList.add('spacer-column');
|
||||||
|
headerRow.appendChild(spacerHeader);
|
||||||
|
|
||||||
|
const sportNameHeader = document.createElement('th');
|
||||||
|
sportNameHeader.textContent = "Sport";
|
||||||
|
headerRow.appendChild(sportNameHeader);
|
||||||
|
|
||||||
|
const dateHeader = document.createElement('th');
|
||||||
|
dateHeader.textContent = "Date";
|
||||||
|
headerRow.appendChild(dateHeader);
|
||||||
|
|
||||||
|
gamesListTable.appendChild(headerRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function listGame(game, row) {
|
||||||
|
const teamsCell = document.createElement('td');
|
||||||
|
const team1NameSpan = document.createElement('span');
|
||||||
|
Data.getTeam(game.team1ID)
|
||||||
|
.then(data => team1NameSpan.textContent = data.name);
|
||||||
|
teamsCell.appendChild(team1NameSpan);
|
||||||
|
const team2NameSpan = document.createElement('span');
|
||||||
|
Data.getTeam(game.team2ID)
|
||||||
|
.then(data => team2NameSpan.textContent = data.name);
|
||||||
|
teamsCell.appendChild(team2NameSpan);
|
||||||
|
row.appendChild(teamsCell);
|
||||||
|
|
||||||
|
const scoresCell = document.createElement('td');
|
||||||
|
const team1ScoreSpan = document.createElement('span');
|
||||||
|
team1ScoreSpan.textContent = game.team1Score;
|
||||||
|
scoresCell.appendChild(team1ScoreSpan);
|
||||||
|
const team2ScoreSpan = document.createElement('span');
|
||||||
|
team2ScoreSpan.textContent = game.team2Score;
|
||||||
|
scoresCell.appendChild(team2ScoreSpan);
|
||||||
|
row.appendChild(scoresCell);
|
||||||
|
|
||||||
|
const spacerCell = document.createElement('td');
|
||||||
|
row.appendChild(spacerCell);
|
||||||
|
|
||||||
|
const sportCell = document.createElement('td');
|
||||||
|
const sportSpan = document.createElement('span');
|
||||||
|
const divisionSpan = document.createElement('span');
|
||||||
|
divisionSpan.classList.add('flat-content');
|
||||||
|
const divisionNameSpan = document.createElement('span');
|
||||||
|
const divisionGenderSpan = document.createElement('span');
|
||||||
|
divisionSpan.appendChild(divisionNameSpan);
|
||||||
|
divisionSpan.appendChild(divisionGenderSpan);
|
||||||
|
Data.getDivision(game.divisionID)
|
||||||
|
.then(data => {
|
||||||
|
Data.getSportName(data.sportID)
|
||||||
|
.then(data => sportSpan.textContent = data);
|
||||||
|
divisionNameSpan.textContent = data.name;
|
||||||
|
divisionGenderSpan.textContent = getGenderLetter(data.gender.name);
|
||||||
|
});
|
||||||
|
sportCell.appendChild(sportSpan);
|
||||||
|
sportCell.appendChild(divisionSpan);
|
||||||
|
row.appendChild(sportCell);
|
||||||
|
|
||||||
|
const dateCell = document.createElement('td');
|
||||||
|
const yearSpan = document.createElement('span');
|
||||||
|
yearSpan.textContent = game.date.slice(0,4);
|
||||||
|
dateCell.appendChild(yearSpan);
|
||||||
|
const dateSpan = document.createElement('span');
|
||||||
|
dateSpan.textContent = game.date.slice(5);
|
||||||
|
dateCell.appendChild(dateSpan);
|
||||||
|
row.appendChild(dateCell);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addGame() {
|
||||||
|
window.location.href = "/manage/game";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function editGame(id) {
|
||||||
|
window.location.href = `/manage/game?game=${id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function listItems() {
|
||||||
|
const gamesList = await Data.getGamesByUser();
|
||||||
|
|
||||||
|
await listGameHeaders();
|
||||||
|
|
||||||
|
gamesList.forEach(game => {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
|
||||||
|
listGame(game, row);
|
||||||
|
|
||||||
|
const manageCell = document.createElement('td');
|
||||||
|
|
||||||
|
const editSpan = document.createElement('span');
|
||||||
|
const editButton = document.createElement('button');
|
||||||
|
editButton.textContent = "E";
|
||||||
|
editButton.addEventListener('click', () => {
|
||||||
|
editGame(game.id);
|
||||||
|
});
|
||||||
|
editSpan.appendChild(editButton);
|
||||||
|
manageCell.appendChild(editSpan);
|
||||||
|
|
||||||
|
row.appendChild(manageCell);
|
||||||
|
|
||||||
|
gamesListTable.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
listItems();
|
||||||
|
|
||||||
|
addNewButton.addEventListener('click', () => addGame());
|
||||||
|
manageAccountButton.addEventListener('click', () => {
|
||||||
|
window.location.href = '/manage/account';
|
||||||
|
});
|
|
@ -21,7 +21,6 @@ async function initializeForm() {
|
||||||
|
|
||||||
Form.populateSports(sportDropdown, team.sportID);
|
Form.populateSports(sportDropdown, team.sportID);
|
||||||
|
|
||||||
console.log(team.sportID);
|
|
||||||
Form.addHiddenValue('team', teamID, submissionForm);
|
Form.addHiddenValue('team', teamID, submissionForm);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -36,3 +36,12 @@ form {
|
||||||
#delete-button {
|
#delete-button {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-section-checkbox {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-checkbox {
|
||||||
|
width: auto;
|
||||||
|
}
|
|
@ -26,7 +26,5 @@ tr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#actions-div {
|
#actions-div {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
|
@ -17,4 +17,17 @@ a {
|
||||||
|
|
||||||
.flat-content {
|
.flat-content {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-to-right {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#actions-div {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-button {
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#admin-checkbox-section {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
const passport = require('passport');
|
||||||
|
const app = require('../app');
|
||||||
|
const accounts = require('./../database/accounts/accounts');
|
||||||
|
|
||||||
|
|
||||||
|
function adminLoggedIn(req, res, next) {
|
||||||
|
if (req.user && req.user[2]) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
req.flash('error', 'An admin account is required to access this page.');
|
||||||
|
res.redirect('/auth/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get('/', adminLoggedIn, (req, res, next) => {
|
||||||
|
res.render
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,39 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
const passport = require('passport');
|
||||||
|
const accounts = require('./../database/accounts/accounts');
|
||||||
|
const app = require('../app');
|
||||||
|
|
||||||
|
|
||||||
|
function adminLoggedIn(req, res, next) {
|
||||||
|
if (req.user && req.user[2]) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
req.flash('error', 'An admin account is required to access this page.');
|
||||||
|
res.redirect('/auth/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get('/login', (req, res, next) => {
|
||||||
|
res.render('accounts/login', { title : "Login", message: req.flash('error') });
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/logout', (req, res, next) => {
|
||||||
|
req.logout();
|
||||||
|
res.redirect("/");
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/login',
|
||||||
|
passport.authenticate('local', {
|
||||||
|
failureRedirect: '/auth/login',
|
||||||
|
successRedirect: '/',
|
||||||
|
failureFlash: "Invalid email or password.",
|
||||||
|
}),
|
||||||
|
(req, res, next) => {
|
||||||
|
console.log(req.user);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -6,7 +6,26 @@ var genders = require('../database/scores/genders');
|
||||||
var divisions = require('../database/scores/divisions');
|
var divisions = require('../database/scores/divisions');
|
||||||
var teams = require('../database/scores/teams');
|
var teams = require('../database/scores/teams');
|
||||||
var games = require('../database/scores/games');
|
var games = require('../database/scores/games');
|
||||||
|
var accounts = require('../database/accounts/accounts');
|
||||||
|
|
||||||
|
function adminLoggedIn(req, res, next) {
|
||||||
|
if (req.user && req.user[2]) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
req.flash('error', 'An admin account is required to access this page.');
|
||||||
|
res.redirect('/auth/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function userLoggedIn(req, res, next) {
|
||||||
|
if (req.user) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.redirect('/auth/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
router.get('/sports', function(req, res, next) {
|
router.get('/sports', function(req, res, next) {
|
||||||
sports.retrieveAll()
|
sports.retrieveAll()
|
||||||
|
@ -52,8 +71,9 @@ router.get('/team', function(req, res, next) {
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/games', function(req, res, next) {
|
router.get('/games', function(req, res, next) {
|
||||||
games.retrieve(req.query.team, req.query.division, req.query.season)
|
const userID = req.user ? req.user[0] : null;
|
||||||
.then(data => res.json(data));
|
if(req.query.user) games.retrieveByUser(userID).then(data => res.json(data));
|
||||||
|
else games.retrieve(req.query.team, req.query.division, req.query.season).then(data => res.json(data));
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/game', function(req, res, next) {
|
router.get('/game', function(req, res, next) {
|
||||||
|
@ -61,4 +81,22 @@ router.get('/game', function(req, res, next) {
|
||||||
.then(data => res.json(data));
|
.then(data => res.json(data));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.get('/accounts', adminLoggedIn, function(req, res, next) {
|
||||||
|
accounts.retrieveAll()
|
||||||
|
.then(data => res.json(data));
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/account', userLoggedIn, function(req, res, next) {
|
||||||
|
const userIsAdmin = req.user[2];
|
||||||
|
const loggedInAccountID = req.user[0];
|
||||||
|
const requestedAccountID = req.query.account;
|
||||||
|
|
||||||
|
if(!userIsAdmin && loggedInAccountID != requestedAccountID) {
|
||||||
|
res.status(403).send("ACCESS DENIED");
|
||||||
|
} else {
|
||||||
|
accounts.getFromID(req.query.account)
|
||||||
|
.then(data => res.json(data));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
|
@ -3,7 +3,7 @@ var router = express.Router();
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
router.get('/', function(req, res, next) {
|
router.get('/', function(req, res, next) {
|
||||||
res.render('index', { title: 'View Scores' });
|
res.render('index', { title: 'View Scores', userLoggedIn: !!req.user, hideHomeButton: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
121
routes/manage.js
121
routes/manage.js
|
@ -7,19 +7,40 @@ var sports = require('../database/scores/sports');
|
||||||
var divisions = require('../database/scores/divisions');
|
var divisions = require('../database/scores/divisions');
|
||||||
var genders = require('../database/scores/genders');
|
var genders = require('../database/scores/genders');
|
||||||
var teams = require('../database/scores/teams');
|
var teams = require('../database/scores/teams');
|
||||||
|
var accounts = require('../database/accounts/accounts');
|
||||||
|
|
||||||
|
function userLoggedIn(req, res, next) {
|
||||||
|
if (req.user) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.redirect('/auth/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function adminLoggedIn(req, res, next) {
|
||||||
|
if (req.user && req.user[2]) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
req.flash('error', 'An admin account is required to access this page.');
|
||||||
|
res.redirect('/auth/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
router.get('/', function(req, res, next) {
|
router.get('/' ,userLoggedIn, function(req, res, next) {
|
||||||
res.render('manage', { title: 'Score Management' });
|
if(req.user[2]) res.render('manage', { title: 'Score Management', userLoggedIn: !!req.user });
|
||||||
|
else res.render('manage/manage-nonadmin', { title: "My Games", userLoggedIn: !!req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/game', function(req, res, next) {
|
router.get('/game', userLoggedIn, function(req, res, next) {
|
||||||
let title = req.query.game ? 'Edit Game' : 'Submit Score'
|
let title = req.query.game ? 'Edit Game' : 'Submit Score'
|
||||||
|
|
||||||
res.render('manage/addgame', { title });
|
res.render('manage/addgame', { title, userLoggedIn: !!req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/game', function(req, res, next) {
|
router.post('/game', userLoggedIn, function(req, res, next) {
|
||||||
const seasonID = req.body['year'];
|
const seasonID = req.body['year'];
|
||||||
const sportID = req.body['sport'];
|
const sportID = req.body['sport'];
|
||||||
const gender = (req.body['gender'] == "female") ? genders.FEMALE : genders.MALE;
|
const gender = (req.body['gender'] == "female") ? genders.FEMALE : genders.MALE;
|
||||||
|
@ -29,23 +50,33 @@ router.post('/game', function(req, res, next) {
|
||||||
const team1Score = req.body['team1-score'];
|
const team1Score = req.body['team1-score'];
|
||||||
const team2ID = req.body['team2'];
|
const team2ID = req.body['team2'];
|
||||||
const team2Score = req.body['team2-score'];
|
const team2Score = req.body['team2-score'];
|
||||||
|
const userID = req.user[0];
|
||||||
|
|
||||||
const id = req.body['game'];
|
const id = req.body['game'];
|
||||||
const remove = req.body['delete'];
|
const remove = req.body['remove'];
|
||||||
|
|
||||||
if(remove) games.remove(id)
|
const loggedInUserID = req.user[0];
|
||||||
.then(res.redirect("/manage"));
|
const loggedInUserIsAdmin = req.user[2];
|
||||||
else if(id) games.edit(id, divisionId, seasonID, date, team1ID, team2ID, team1Score, team2Score)
|
|
||||||
.then(res.redirect('/manage'));
|
games.getFromID(id)
|
||||||
else games.add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score)
|
.then(game => {
|
||||||
.then(res.redirect("/manage"));
|
if(!loggedInUserIsAdmin && loggedInUserID != game.submitterID) {
|
||||||
|
res.status(403).send("ACCESS DENIED");
|
||||||
|
}
|
||||||
|
else if(remove) games.remove(id)
|
||||||
|
.then(res.redirect("/manage"));
|
||||||
|
else if(id) games.edit(id, divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score)
|
||||||
|
.then(res.redirect('/manage'));
|
||||||
|
else games.add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, userID)
|
||||||
|
.then(res.redirect("/manage"));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/season', function(req, res, next) {
|
router.get('/season', adminLoggedIn, function(req, res, next) {
|
||||||
res.render('manage/addseason', { title: 'Add Season', currentYear : (new Date()).getFullYear() });
|
res.render('manage/addseason', { title: 'Add Season', currentYear : (new Date()).getFullYear(), userLoggedIn: !!req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/season', function(req, res, next) {
|
router.post('/season', adminLoggedIn, function(req, res, next) {
|
||||||
const year = req.body['year'];
|
const year = req.body['year'];
|
||||||
|
|
||||||
const seasonID = req.body['season'];
|
const seasonID = req.body['season'];
|
||||||
|
@ -55,11 +86,11 @@ router.post('/season', function(req, res, next) {
|
||||||
else seasons.add(year).then(res.redirect("/manage"));
|
else seasons.add(year).then(res.redirect("/manage"));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/sport', function(req, res, next) {
|
router.get('/sport', adminLoggedIn, function(req, res, next) {
|
||||||
res.render('manage/addsport', { title: 'Add Sport' });
|
res.render('manage/addsport', { title: 'Add Sport', userLoggedIn: !!req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/sport', function(req, res, next) {
|
router.post('/sport', adminLoggedIn, function(req, res, next) {
|
||||||
const name = req.body['name'];
|
const name = req.body['name'];
|
||||||
const id = req.body['sport'];
|
const id = req.body['sport'];
|
||||||
const remove = req.body['remove'];
|
const remove = req.body['remove'];
|
||||||
|
@ -69,13 +100,13 @@ router.post('/sport', function(req, res, next) {
|
||||||
else sports.add(name).then(res.redirect('/manage'));
|
else sports.add(name).then(res.redirect('/manage'));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/division', function(req, res, next) {
|
router.get('/division', adminLoggedIn, function(req, res, next) {
|
||||||
let title = req.query.division ? 'Edit Division' : 'Add Division'
|
let title = req.query.division ? 'Edit Division' : 'Add Division'
|
||||||
|
|
||||||
res.render('manage/adddivision', { title });
|
res.render('manage/adddivision', { title, userLoggedIn: !!req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/division', function(req, res, next) {
|
router.post('/division', adminLoggedIn, function(req, res, next) {
|
||||||
const name = req.body['name'];
|
const name = req.body['name'];
|
||||||
const sport = req.body['sport'];
|
const sport = req.body['sport'];
|
||||||
const genderName = req.body['gender'];
|
const genderName = req.body['gender'];
|
||||||
|
@ -100,13 +131,13 @@ router.post('/division', function(req, res, next) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/team', function(req, res, next) {
|
router.get('/team', adminLoggedIn, function(req, res, next) {
|
||||||
let title = req.query.team ? 'Edit Team' : 'Add Team'
|
let title = req.query.team ? 'Edit Team' : 'Add Team'
|
||||||
|
|
||||||
res.render('manage/addteam', { title });
|
res.render('manage/addteam', { title, userLoggedIn: !!req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/team', function(req, res, next) {
|
router.post('/team', adminLoggedIn, function(req, res, next) {
|
||||||
const name = req.body['name'];
|
const name = req.body['name'];
|
||||||
const sport = req.body['sport'];
|
const sport = req.body['sport'];
|
||||||
|
|
||||||
|
@ -118,4 +149,46 @@ router.post('/team', function(req, res, next) {
|
||||||
else teams.add(name, sport).then(res.redirect("/manage"));
|
else teams.add(name, sport).then(res.redirect("/manage"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/account', userLoggedIn, (req, res, next) => {
|
||||||
|
const userIsAdmin = req.user[2];
|
||||||
|
const accountID = req.user[0];
|
||||||
|
|
||||||
|
if(userIsAdmin) {
|
||||||
|
let title = req.query.account ? 'Manage User' : 'Create User'
|
||||||
|
|
||||||
|
res.render('accounts/createuser', { title, userLoggedIn: !!req.user });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let title = 'Manage Account';
|
||||||
|
|
||||||
|
res.render('accounts/createuser', { title, accountID, userLoggedIn: !!req.user });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/account', userLoggedIn, (req, res, next) => {
|
||||||
|
const email = req.body.email;
|
||||||
|
const password = req.body.password;
|
||||||
|
|
||||||
|
const accountID = req.body.account;
|
||||||
|
const remove = req.body.remove;
|
||||||
|
|
||||||
|
const loggedInAccountIsAdmin = req.user[2];
|
||||||
|
const loggedInAccountID = req.user[0];
|
||||||
|
|
||||||
|
console.log(accountID);
|
||||||
|
console.log(loggedInAccountID);
|
||||||
|
|
||||||
|
|
||||||
|
if(!loggedInAccountIsAdmin && accountID != loggedInAccountID) {
|
||||||
|
res.status(403).send("ACCESS DENIED");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const isAdmin = loggedInAccountIsAdmin ? !!req.body.admin : false;
|
||||||
|
|
||||||
|
if(remove) accounts.remove(accountID).then(res.redirect('/manage'));
|
||||||
|
if(accountID) accounts.edit(accountID, email, password, isAdmin).then(res.redirect('/manage'));
|
||||||
|
else accounts.create(req.body.email, req.body.password, !!req.body.admin).then(res.redirect('/manage'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
extends ../layout
|
||||||
|
|
||||||
|
block stylesheets
|
||||||
|
link(rel='stylesheet', href='/stylesheets/submit.css')
|
||||||
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
|
block content
|
||||||
|
form#submission-form(action='/manage/account', method='POST')
|
||||||
|
if accountID
|
||||||
|
input#account-id(type="hidden" name="account" value=accountID)
|
||||||
|
span(class='form-section')
|
||||||
|
label Email
|
||||||
|
span(class='form-section-input')
|
||||||
|
input#email-textbox(type="email", name="email" disabled)
|
||||||
|
span(class='form-section')
|
||||||
|
label Password
|
||||||
|
span(class='form-section-input' )
|
||||||
|
input#password-textbox(type="password" name="password" disabled)
|
||||||
|
span#admin-checkbox-section(class='form-section')
|
||||||
|
span(class='form-section-checkbox')
|
||||||
|
input#admin-checkbox(type="checkbox" name="admin" disabled)
|
||||||
|
label(for="admin-checkbox") Grant admin privileges
|
||||||
|
span(class='form-section')
|
||||||
|
button#submit-button(type="submit" disabled) Submit
|
||||||
|
span(class='form-section')
|
||||||
|
button#delete-button(type="delete" disabled) Delete
|
||||||
|
|
||||||
|
block scripts
|
||||||
|
script(src='/scripts/manage/account.js' type="module")
|
|
@ -0,0 +1,19 @@
|
||||||
|
extends ../layout
|
||||||
|
|
||||||
|
block stylesheets
|
||||||
|
link(rel='stylesheet', href='/stylesheets/submit.css')
|
||||||
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
|
block content
|
||||||
|
form(action='/auth/login', method='POST')
|
||||||
|
span(class='form-section')
|
||||||
|
label Email
|
||||||
|
span(class='form-section-input')
|
||||||
|
input(type="email", name="email")
|
||||||
|
span(class='form-section')
|
||||||
|
label Password
|
||||||
|
span(class='form-section-input')
|
||||||
|
input(type="password", name="password")
|
||||||
|
.error #{message}
|
||||||
|
span(class='form-section')
|
||||||
|
button#submit-button(type="submit") Submit
|
|
@ -4,13 +4,13 @@ block stylesheets
|
||||||
link(rel='stylesheet', href='/stylesheets/index.css')
|
link(rel='stylesheet', href='/stylesheets/index.css')
|
||||||
link(rel='stylesheet', href='/stylesheets/form.css')
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
|
block actions
|
||||||
|
if userLoggedIn
|
||||||
|
button#add-score-button Submit score
|
||||||
|
button#manage-button Manage...
|
||||||
|
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div#mobile-view
|
|
||||||
div#header-div
|
|
||||||
h1 Score Tracker
|
|
||||||
div#actions-div
|
|
||||||
button#add-score-button +
|
|
||||||
button#manage-button Manage
|
|
||||||
div
|
div
|
||||||
span(class='form-section')
|
span(class='form-section')
|
||||||
label Year
|
label Year
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
doctype html
|
doctype html
|
||||||
html
|
html
|
||||||
head
|
head
|
||||||
title= title
|
title= title + ' - Score Tracker'
|
||||||
meta(name='viewport', content='width=device-width, initial-scale=1')
|
meta(name='viewport', content='width=device-width, initial-scale=1')
|
||||||
link(rel='stylesheet', href='/stylesheets/style.css')
|
link(rel='stylesheet', href='/stylesheets/style.css')
|
||||||
block stylesheets
|
block stylesheets
|
||||||
body
|
body
|
||||||
block content
|
div#mobile-view
|
||||||
|
div#actions-div
|
||||||
|
if !hideHomeButton
|
||||||
|
button#home-button Home
|
||||||
|
block actions
|
||||||
|
if userLoggedIn
|
||||||
|
button#logout-button Log out
|
||||||
|
else if userLoggedIn !== undefined
|
||||||
|
button#login-button Log in
|
||||||
|
h1 #{title}
|
||||||
|
block content
|
||||||
block scripts
|
block scripts
|
||||||
|
script(src='/scripts/main.js' type="module")
|
||||||
|
|
|
@ -5,8 +5,6 @@ block stylesheets
|
||||||
link(rel='stylesheet', href='/stylesheets/form.css')
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div#mobile-view
|
|
||||||
h1 Management Panel
|
|
||||||
div
|
div
|
||||||
span(class='form-section')
|
span(class='form-section')
|
||||||
label Category
|
label Category
|
||||||
|
@ -17,6 +15,7 @@ block content
|
||||||
option(value="divisions") Divisions
|
option(value="divisions") Divisions
|
||||||
option(value="teams") Teams
|
option(value="teams") Teams
|
||||||
option(value="games") Games
|
option(value="games") Games
|
||||||
|
option(value="accounts") Accounts
|
||||||
div
|
div
|
||||||
h2#table-header
|
h2#table-header
|
||||||
table#items-list
|
table#items-list
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
block stylesheets
|
block stylesheets
|
||||||
link(rel='stylesheet', href='/stylesheets/submit.css')
|
link(rel='stylesheet', href='/stylesheets/submit.css')
|
||||||
link(rel='stylesheet', href='/stylesheets/form.css')
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div#mobile-view
|
|
||||||
h1 #{title}
|
|
||||||
form#submission-form(action='./division', method='POST')
|
form#submission-form(action='./division', method='POST')
|
||||||
span(class='form-section')
|
span(class='form-section')
|
||||||
label Sport
|
label Sport
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
block stylesheets
|
block stylesheets
|
||||||
link(rel='stylesheet', href='/stylesheets/submit.css')
|
link(rel='stylesheet', href='/stylesheets/submit.css')
|
||||||
link(rel='stylesheet', href='/stylesheets/form.css')
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div#mobile-view
|
form#submission-form(action='./game', method='POST')
|
||||||
h1 #{title}
|
|
||||||
form#submission-form(action='./submitgame', method='POST')
|
|
||||||
span(class='form-section')
|
span(class='form-section')
|
||||||
label Year
|
label Year
|
||||||
span(class='form-section-input')
|
span(class='form-section-input')
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
block stylesheets
|
block stylesheets
|
||||||
link(rel='stylesheet', href='/stylesheets/submit.css')
|
link(rel='stylesheet', href='/stylesheets/submit.css')
|
||||||
link(rel='stylesheet', href='/stylesheets/form.css')
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div#mobile-view
|
|
||||||
h1 #{title}
|
|
||||||
form(action='./season', method='POST')
|
form(action='./season', method='POST')
|
||||||
span(class='form-section')
|
span(class='form-section')
|
||||||
label Ending year
|
label Ending year
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
block stylesheets
|
block stylesheets
|
||||||
link(rel='stylesheet', href='/stylesheets/submit.css')
|
link(rel='stylesheet', href='/stylesheets/submit.css')
|
||||||
link(rel='stylesheet', href='/stylesheets/form.css')
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div#mobile-view
|
|
||||||
h1#main-header Add Sport
|
|
||||||
form#submission-form(action='./sport', method='POST')
|
form#submission-form(action='./sport', method='POST')
|
||||||
span(class='form-section')
|
span(class='form-section')
|
||||||
label Sport name
|
label Sport name
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
block stylesheets
|
block stylesheets
|
||||||
link(rel='stylesheet', href='/stylesheets/submit.css')
|
link(rel='stylesheet', href='/stylesheets/submit.css')
|
||||||
link(rel='stylesheet', href='/stylesheets/form.css')
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div#mobile-view
|
|
||||||
h1 #{title}
|
|
||||||
form#submission-form(action='./team', method='POST')
|
form#submission-form(action='./team', method='POST')
|
||||||
span(class='form-section')
|
span(class='form-section')
|
||||||
label Sport
|
label Sport
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
extends ../layout
|
||||||
|
|
||||||
|
block stylesheets
|
||||||
|
link(rel='stylesheet', href='/stylesheets/manage.css')
|
||||||
|
link(rel='stylesheet', href='/stylesheets/form.css')
|
||||||
|
|
||||||
|
block actions
|
||||||
|
button#manage-account-button(class="send-to-right") Manage account
|
||||||
|
|
||||||
|
block content
|
||||||
|
div
|
||||||
|
table#games-list
|
||||||
|
div
|
||||||
|
button#add-new-button Add new...
|
||||||
|
|
||||||
|
block scripts
|
||||||
|
script(src='/scripts/manage/manage-nonadmin.js' type="module")
|
Reference in New Issue