Merge branch 'feature/easier-score-submission' into 'develop'

Add ability to submit score without account

See merge request sudoer777/score-tracker!13
main
Ethan Reece 2021-12-07 18:14:30 +00:00
commit 527fadf67e
10 changed files with 111 additions and 30 deletions

View File

@ -6,6 +6,8 @@ PGPASSWORD=dbuserpassword
PGDATABASE=mydatabase PGDATABASE=mydatabase
PGPORT=5432 PGPORT=5432
PUBLIC_SUBMIT_PAGE=false
#MAIL_FROM=fromaddress@example.com #MAIL_FROM=fromaddress@example.com
#MAIL_HOST=smtp.smtphost.net #MAIL_HOST=smtp.smtphost.net
#MAIL_PORT=465 #MAIL_PORT=465

View File

@ -40,7 +40,7 @@ async function checkForDatabaseInitialization() {
let latestMigration; let latestMigration;
try { try {
const latestMigrationQuery = `SELECT value FROM metadata WHERE property = 'latest_migration';`; const latestMigrationQuery = `SELECT value FROM metadata WHERE property = 'latest_migration';`;
latestMigration = (await executeQuery(latestMigrationQuery))[0][0]; latestMigration = +((await executeQuery(latestMigrationQuery))[0][0]);
} catch { } catch {
latestMigration = 0; latestMigration = 0;
} }
@ -54,7 +54,7 @@ async function performMigrations(currentMigration) {
const migrationFileList = fs.readdirSync('database/migrations'); const migrationFileList = fs.readdirSync('database/migrations');
const latestMigration = +migrationFileList[migrationFileList.length - 1].slice(0, 1); const latestMigration = +migrationFileList[migrationFileList.length - 1].slice(0, 1);
for(let i = currentMigration + 1; i <= latestMigration; i++) { for(let i = +currentMigration + 1; i <= latestMigration; i++) {
const sql = fs.readFileSync(`database/migrations/${i}.sql`).toString(); const sql = fs.readFileSync(`database/migrations/${i}.sql`).toString();
await executeQuery(sql); await executeQuery(sql);
console.log(`Performed database migration ${i}`); console.log(`Performed database migration ${i}`);

View File

@ -15,14 +15,14 @@ scores:
*season_id* | school_year *season_id* | school_year
games: games:
*game_id* | ~division_id~ | ~season_id~ | game_date | ~team1_id~ | ~team2_id~ | team1_score | team2_score | ~submitter_id~ | updated_timestamp *game_id* | ~division_id~ | ~season_id~ | game_date | ~team1_id~ | ~team2_id~ | team1_score | team2_score | ~submitter_id~ | updated_timestamp | submitter_name
accounts: accounts:
users: users:
*user_id* | email | password | admin *user_id* | email | password | admin | full_name
*/ */
@ -91,7 +91,8 @@ CREATE TABLE IF NOT EXISTS scores.games(
team2_id BIGINT NOT NULL, team2_id BIGINT NOT NULL,
team1_score INTEGER NOT NULL, team1_score INTEGER NOT NULL,
team2_score INTEGER NOT NULL, team2_score INTEGER NOT NULL,
submitter_id BIGINT NOT NULL, submitter_name TEXT,
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
@ -118,6 +119,6 @@ CREATE TABLE IF NOT EXISTS metadata(
); );
INSERT INTO metadata(property, value) INSERT INTO metadata(property, value)
VALUES("latest_migration", "2"); VALUES("latest_migration", "3");
COMMIT; COMMIT;

View File

@ -0,0 +1,15 @@
/* ADD OPTIONAL SUBMITTER NAME COLUMN IN GAMES TABLE */
BEGIN;
ALTER TABLE scores.games ALTER COLUMN submitter_id DROP NOT NULL;
ALTER TABLE scores.games
ADD COLUMN submitter_name TEXT;
UPDATE metadata
SET value = '3'
WHERE property = 'latest_migration';
COMMIT;

View File

@ -5,7 +5,7 @@ const database = require('./../database');
class Game { class Game {
constructor(id, date, team1ID, team2ID, team1Score, team2Score, divisionID, seasonID, submitterID) { constructor(id, date, team1ID, team2ID, team1Score, team2Score, divisionID, seasonID, submitterID, submitterName) {
this.id = id; this.id = id;
this.date = date; this.date = date;
this.team1ID = team1ID; this.team1ID = team1ID;
@ -15,17 +15,26 @@ class Game {
this.divisionID = divisionID; this.divisionID = divisionID;
this.seasonID = seasonID; this.seasonID = seasonID;
this.submitterID = submitterID; this.submitterID = submitterID;
this.submitterName = submitterName;
} }
} }
async function add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, userID) { async function add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, submitterID, submitterName = undefined) {
const query = `INSERT INTO scores.games(division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_id) let id;
VALUES($1, $2, $3, $4, $5, $6, $7, $8) if(submitterName) {
RETURNING game_id;`; const query = `INSERT INTO scores.games(division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_name)
VALUES($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING game_id;`;
id = (await database.executeQuery(query, [divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, submitterName]))[0][0];
} else {
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, $8)
RETURNING game_id;`;
id = (await database.executeQuery(query, [divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, submitterID]))[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);
} }
@ -41,14 +50,14 @@ async function retrieve(teamID, divisionID, seasonID) {
let table; let table;
if(teamID && divisionID && seasonID) { if(teamID && divisionID && seasonID) {
const query = `SELECT game_id, division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_id const query = `SELECT game_id, division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_id, submitter_name
FROM scores.games FROM scores.games
WHERE (team1_id = $1 OR team2_id = $1) AND division_id = $2 AND season_id = $3 WHERE (team1_id = $1 OR team2_id = $1) AND division_id = $2 AND season_id = $3
ORDER BY game_date DESC;`; ORDER BY game_date DESC;`;
table = await database.executeQuery(query, [teamID,divisionID,seasonID]); table = await database.executeQuery(query, [teamID,divisionID,seasonID]);
} }
else { else {
const query = `SELECT game_id, division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_id const query = `SELECT game_id, division_id, season_id, game_date, team1_id, team2_id, team1_score, team2_score, submitter_id, submitter_name
FROM scores.games FROM scores.games
ORDER BY game_date DESC;`; ORDER BY game_date DESC;`;
table = await database.executeQuery(query); table = await database.executeQuery(query);
@ -63,10 +72,10 @@ async function retrieve(teamID, divisionID, seasonID) {
const teamScore = opponentIsTeam2 ? row[6] : row[7]; const teamScore = opponentIsTeam2 ? row[6] : row[7];
const opponentScore = opponentIsTeam2 ? row[7] : row[6]; const opponentScore = opponentIsTeam2 ? row[7] : row[6];
gamesList.push(new Game(row[0], row[3].toISOString().slice(0,10), teamID, opponentID, teamScore, opponentScore, row[1], row[2], row[8])); gamesList.push(new Game(row[0], row[3].toISOString().slice(0,10), teamID, opponentID, teamScore, opponentScore, row[1], row[2], row[8], row[9]));
} }
else { else {
gamesList.push(new Game(row[0], row[3].toISOString().slice(0,10), row[4], row[5], row[6], row[7], row[1], row[2], row[8])); gamesList.push(new Game(row[0], row[3].toISOString().slice(0,10), row[4], row[5], row[6], row[7], row[1], row[2], row[8], row[9]));
} }
}); });
return gamesList; return gamesList;

View File

@ -291,8 +291,13 @@ CATEGORIES.push(new Category(
row.appendChild(dateCell); row.appendChild(dateCell);
const submitterCell = document.createElement('td'); const submitterCell = document.createElement('td');
Data.getAccount(game.submitterID) if(game.submitterID) {
.then(data => submitterCell.textContent = data.name); Data.getAccount(game.submitterID)
.then(data => submitterCell.textContent = data.name);
} else {
submitterCell.textContent = game.submitterName;
console.log(game.submitterName);
}
row.appendChild(submitterCell); row.appendChild(submitterCell);
}, },
async function addGame() { async function addGame() {

View File

@ -12,6 +12,7 @@ const team1Dropdown = document.getElementById('team1-dropdown');
const team2Dropdown = document.getElementById('team2-dropdown'); const team2Dropdown = document.getElementById('team2-dropdown');
const team1ScoreTextbox = document.getElementById('team1-score-textbox'); const team1ScoreTextbox = document.getElementById('team1-score-textbox');
const team2ScoreTextbox = document.getElementById('team2-score-textbox'); const team2ScoreTextbox = document.getElementById('team2-score-textbox');
const nameTextbox = document.getElementById('name-textbox');
const submitButton = document.getElementById('submit-button'); const submitButton = document.getElementById('submit-button');
const deleteButton = document.getElementById('delete-button'); const deleteButton = document.getElementById('delete-button');
@ -70,6 +71,9 @@ async function initializeForm() {
team2Dropdown.disabled = false; team2Dropdown.disabled = false;
team1ScoreTextbox.disabled = false; team1ScoreTextbox.disabled = false;
team2ScoreTextbox.disabled = false; team2ScoreTextbox.disabled = false;
if(nameTextbox) {
nameTextbox.disabled = false;
}
sportDropdown.onchange = async () => { sportDropdown.onchange = async () => {
await Form.populateGenders(genderDropdown, sportDropdown.value) await Form.populateGenders(genderDropdown, sportDropdown.value)
@ -89,6 +93,7 @@ async function initializeForm() {
team1ScoreTextbox.addEventListener('keyup', checkDataValidity); team1ScoreTextbox.addEventListener('keyup', checkDataValidity);
team2Dropdown.onchange = checkDataValidity; team2Dropdown.onchange = checkDataValidity;
team2ScoreTextbox.addEventListener('keyup', checkDataValidity); team2ScoreTextbox.addEventListener('keyup', checkDataValidity);
if(nameTextbox) nameTextbox.addEventListener('keyup', checkDataValidity);
checkDataValidity(); checkDataValidity();
} }
@ -112,6 +117,8 @@ async function checkDataValidity() {
if(dateInput.value == "") dataIsValid = false; if(dateInput.value == "") dataIsValid = false;
if(nameTextbox && nameTextbox.value == "") dataIsValid = false;
submitButton.disabled = !dataIsValid; submitButton.disabled = !dataIsValid;
} }

View File

@ -1,9 +1,12 @@
var express = require('express'); var express = require('express');
var router = express.Router(); var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) { router.get('/', function(req, res, next) {
res.render('index', { title: 'View Scores', userLoggedIn: !!req.user, hideHomeButton: true }); res.render('index', { title: 'View Scores', userLoggedIn: !!req.user, hideHomeButton: true });
}); });
router.get('/submit', function(req, res, next) {
res.redirect('/manage/game');
});
module.exports = router; module.exports = router;

View File

@ -12,19 +12,47 @@ var accounts = require('../database/accounts/accounts');
var checkLoginStatus = require('./checkLoginStatus'); var checkLoginStatus = require('./checkLoginStatus');
if (process.env.NODE_ENV !== 'production' || process.env.NODE_ENV !== 'testing') {
require('dotenv').config();
}
router.get('/' ,checkLoginStatus.user, function(req, res, next) { router.get('/' ,checkLoginStatus.user, function(req, res, next) {
if(req.user[2]) res.render('manage', { title: 'Management Panel', userLoggedIn: !!req.user }); if(req.user[2]) res.render('manage', { title: 'Management Panel', userLoggedIn: !!req.user });
else res.render('manage/manage-nonadmin', { title: "My Games", userLoggedIn: !!req.user }); else res.render('manage/manage-nonadmin', { title: "My Games", userLoggedIn: !!req.user });
}); });
router.get('/game', checkLoginStatus.user, function(req, res, next) { router.get('/game', function(req, res, next) {
let title = req.query.game ? 'Edit Game' : 'Submit Score' if(!(process.env.PUBLIC_SUBMIT_PAGE && process.env.PUBLIC_SUBMIT_PAGE.toLowerCase() == 'true')) {
if (req.user) {
next();
}
else {
res.redirect('/auth/login');
}
} else {
next();
}
},
function(req, res, next) {
let title = req.query.game ? 'Edit Game' : 'Submit Score';
res.render('manage/addgame', { title, userLoggedIn: !!req.user, message: req.flash('error') }); res.render('manage/addgame', { title, userLoggedIn: !!req.user, message: req.flash('error') });
}); });
router.post('/game', checkLoginStatus.user, async function(req, res, next) { router.post('/game', function(req, res, next) {
if(!(process.env.PUBLIC_SUBMIT_PAGE && process.env.PUBLIC_SUBMIT_PAGE.toLowerCase() == 'true')) {
if (req.user) {
next();
}
else {
res.redirect('/auth/login');
}
} else {
next();
}
},
async function(req, res, next) {
const id = req.body['game']; const id = req.body['game'];
const remove = req.body['remove']; const remove = req.body['remove'];
@ -38,14 +66,20 @@ router.post('/game', checkLoginStatus.user, async 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 submitterName = req.body['name'];
const loggedInUserID = req.user[0]; let submitterID;
const loggedInUserIsAdmin = req.user[2]; let loggedInUserID;
let loggedInUserIsAdmin;
if(req.user) {
submitterID = req.user[0];
loggedInUserID = req.user[0];
loggedInUserIsAdmin = req.user[2];
}
const game = id ? await games.getFromID(id) : null; const game = id ? await games.getFromID(id) : null;
if(!loggedInUserIsAdmin && game && loggedInUserID != game.submitterID) { if((!loggedInUserIsAdmin && game && loggedInUserID != game.submitterID) || (!req.user && game)) {
res.status(403).send("ACCESS DENIED"); res.status(403).send("ACCESS DENIED");
} }
else if(remove) { else if(remove) {
@ -57,7 +91,7 @@ router.post('/game', checkLoginStatus.user, async function(req, res, next) {
res.redirect('/manage#games'); res.redirect('/manage#games');
} }
else { else {
await games.add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, userID); await games.add(divisionID, seasonID, date, team1ID, team2ID, team1Score, team2Score, submitterID, submitterName);
res.redirect('/'); res.redirect('/');
} }
} catch(err) { } catch(err) {

View File

@ -45,6 +45,11 @@ block content
label Score label Score
span(class='form-section-input') span(class='form-section-input')
input#team2-score-textbox(type="number", name="team2-score", value="0" disabled) input#team2-score-textbox(type="number", name="team2-score", value="0" disabled)
if !userLoggedIn
span(class='form-section')
label Your name
span(class='form-section-input')
input#name-textbox(type="text" name="name" disabled)
.error #{message} .error #{message}
span(class='form-section') span(class='form-section')
button#submit-button(type="submit" disabled) Submit button#submit-button(type="submit" disabled) Submit