restructured user, auth, role models
This commit is contained in:
parent
26edfd46fe
commit
69427f1809
|
|
@ -1,2 +1,3 @@
|
||||||
.idea/
|
.idea/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
backend/.env
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
DB_TEST_USER=dev_user
|
||||||
|
DB_TEST_PASSWORD=dev_password
|
||||||
|
DB_TEST_NAME=dev_db
|
||||||
|
DB_TEST_HOST=127.0.0.1
|
||||||
|
DB_TEST_PORT=5432
|
||||||
|
DB_TEST_DIALECT=postgres
|
||||||
|
|
||||||
|
DB_DEV_USER=dev_user
|
||||||
|
DB_DEV_PASSWORD=dev_password
|
||||||
|
DB_DEV_NAME=dev_db
|
||||||
|
DB_DEV_HOST=127.0.0.1
|
||||||
|
DB_DEV_PORT=5432
|
||||||
|
DB_DEV_DIALECT=postgres
|
||||||
|
|
||||||
|
DB_PROD_USER=prod_user
|
||||||
|
DB_PROD_PASSWORD=prod_password
|
||||||
|
DB_PROD_NAME=prod_db
|
||||||
|
DB_PROD_HOST=prod-db-server.com
|
||||||
|
DB_PROD_PORT=5432
|
||||||
|
DB_PROD_DIALECT=postgres
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const cors = require("cors");
|
const cors = require("cors");
|
||||||
const bcrypt = require("bcryptjs");
|
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
|
@ -14,13 +13,7 @@ app.use(express.json());
|
||||||
// parse requests of content-type - application/x-www-form-urlencoded
|
// parse requests of content-type - application/x-www-form-urlencoded
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
// database
|
// db.sequelize.sync();
|
||||||
const db = require("./models");
|
|
||||||
const Role = db.Role;
|
|
||||||
const User = db.User;
|
|
||||||
const PitchType = db.PitchType;
|
|
||||||
|
|
||||||
db.sequelize.sync();
|
|
||||||
// force: true will drop the table if it already exists
|
// force: true will drop the table if it already exists
|
||||||
// db.sequelize.sync({force: true}).then(() => {
|
// db.sequelize.sync({force: true}).then(() => {
|
||||||
// console.log('Drop and Re-sync Database with { force: true }');
|
// console.log('Drop and Re-sync Database with { force: true }');
|
||||||
|
|
@ -38,33 +31,33 @@ require('./routes/user.routes')(app);
|
||||||
require('./routes/pitchType.routes')(app);
|
require('./routes/pitchType.routes')(app);
|
||||||
require('./routes/bullpenSession.routes')(app);
|
require('./routes/bullpenSession.routes')(app);
|
||||||
|
|
||||||
function initial() {
|
// function initial() {
|
||||||
Role.bulkCreate([
|
// Role.bulkCreate([
|
||||||
{ name: 'user' },
|
// { name: 'user' },
|
||||||
{ name: 'administrator' },
|
// { name: 'administrator' },
|
||||||
]);
|
// ]);
|
||||||
User.bulkCreate([
|
// User.bulkCreate([
|
||||||
{ firstName: 'Nolan', lastName: 'Ryan', dateOfBirth: new Date(1947, 1, 31), email: 'ryan.nolan@bullpen.com', password: bcrypt.hashSync('nolan', 8) },
|
// { firstName: 'Nolan', lastName: 'Ryan', dateOfBirth: new Date(1947, 1, 31), email: 'ryan.nolan@bullpen.com', password: bcrypt.hashSync('nolan', 8) },
|
||||||
{ firstName: 'Sandy', lastName: 'Koufax', dateOfBirth: new Date(1935, 12, 30), email: 'sandy.koufax@bullpen.com', password: bcrypt.hashSync('sandy', 8) },
|
// { firstName: 'Sandy', lastName: 'Koufax', dateOfBirth: new Date(1935, 12, 30), email: 'sandy.koufax@bullpen.com', password: bcrypt.hashSync('sandy', 8) },
|
||||||
{ firstName: 'Pedro', lastName: 'Martinez', dateOfBirth: new Date(1971, 10, 25), email: 'pedro.martinez@bullpen.com', password: bcrypt.hashSync('pedro', 8) },
|
// { firstName: 'Pedro', lastName: 'Martinez', dateOfBirth: new Date(1971, 10, 25), email: 'pedro.martinez@bullpen.com', password: bcrypt.hashSync('pedro', 8) },
|
||||||
{ firstName: 'randy', lastName: 'johnson', dateOfBirth: new Date(1963, 9, 10), email: 'randy.johnson@bullpen.com', password: bcrypt.hashSync('randy', 8) }
|
// { firstName: 'randy', lastName: 'johnson', dateOfBirth: new Date(1963, 9, 10), email: 'randy.johnson@bullpen.com', password: bcrypt.hashSync('randy', 8) }
|
||||||
]);
|
// ]);
|
||||||
|
//
|
||||||
User.findAll().then(users => {
|
// User.findAll().then(users => {
|
||||||
users.forEach(user => {
|
// users.forEach(user => {
|
||||||
user.setRoles([1]);
|
// user.setRoles([1]);
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
PitchType.bulkCreate([
|
// PitchType.bulkCreate([
|
||||||
{ name: 'Fastball', abbreviation: 'FB' },
|
// { name: 'Fastball', abbreviation: 'FB' },
|
||||||
{ name: 'Curveball', abbreviation: 'CB' },
|
// { name: 'Curveball', abbreviation: 'CB' },
|
||||||
{ name: 'Slider', abbreviation: 'SL' },
|
// { name: 'Slider', abbreviation: 'SL' },
|
||||||
{ name: 'Changeup', abbreviation: 'CH' },
|
// { name: 'Changeup', abbreviation: 'CH' },
|
||||||
{ name: 'Cutter', abbreviation: 'CUT' },
|
// { name: 'Cutter', abbreviation: 'CUT' },
|
||||||
{ name: 'Sweeper', abbreviation: 'SW' },
|
// { name: 'Sweeper', abbreviation: 'SW' },
|
||||||
{ name: 'Slurve', abbreviation: 'SLV' },
|
// { name: 'Slurve', abbreviation: 'SLV' },
|
||||||
]);
|
// ]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,31 @@
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
development: {
|
|
||||||
dialect: 'postgres',
|
|
||||||
username: 'tester',
|
|
||||||
password: 'test123',
|
|
||||||
database: 'bullpen',
|
|
||||||
host: 'localhost',
|
|
||||||
port: 15432,
|
|
||||||
logging: false,
|
|
||||||
},
|
|
||||||
test: {
|
test: {
|
||||||
dialect: 'postgres',
|
username: process.env.DB_TEST_USER,
|
||||||
username: 'test',
|
password: process.env.DB_TEST_PASSWORD,
|
||||||
password: 'test123!',
|
database: process.env.DB_TEST_NAME,
|
||||||
database: 'bullpen',
|
host: process.env.DB_TEST_HOST,
|
||||||
host: 'localhost',
|
port: process.env.DB_TEST_PORT,
|
||||||
port: 5432,
|
dialect: process.env.DB_TEST_DIALECT,
|
||||||
logging: false,
|
logging: false,
|
||||||
},
|
},
|
||||||
staging: {
|
development: {
|
||||||
username: process.env.DB_USER,
|
username: process.env.DB_DEV_USER,
|
||||||
password: process.env.DB_PASS,
|
password: process.env.DB_DEV_PASSWORD,
|
||||||
database: process.env.DB_NAME,
|
database: process.env.DB_DEV_NAME,
|
||||||
host: process.env.DB_HOST,
|
host: process.env.DB_DEV_HOST,
|
||||||
dialect: process.env.DB_DIALECT,
|
port: process.env.DB_DEV_PORT,
|
||||||
|
dialect: process.env.DB_DEV_DIALECT,
|
||||||
logging: false,
|
logging: false,
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
username: process.env.DB_USER,
|
username: process.env.DB_PROD_USER,
|
||||||
password: process.env.DB_PASS,
|
password: process.env.DB_PROD_PASSWORD,
|
||||||
database: process.env.DB_NAME,
|
database: process.env.DB_PROD_NAME,
|
||||||
host: process.env.DB_HOST,
|
host: process.env.DB_PROD_HOST,
|
||||||
dialect: process.env.DB_DIALECT,
|
port: process.env.DB_PROD_PORT,
|
||||||
|
dialect: process.env.DB_PROD_DIALECT,
|
||||||
logging: false,
|
logging: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
const db = require("../models/index");
|
const db = require("../models/index");
|
||||||
const config = require("../config/auth.config");
|
const config = require("../config/auth.config");
|
||||||
const { User: User, Role: Role, RefreshToken: RefreshToken } = db;
|
const { Auth: Auth, User: User, Role: Role, RefreshToken: RefreshToken } = db;
|
||||||
|
|
||||||
const Op = db.Sequelize.Op;
|
const Op = db.Sequelize.Op;
|
||||||
|
|
||||||
|
|
@ -8,83 +8,90 @@ const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
exports.register = (req, res) => {
|
exports.register = (req, res) => {
|
||||||
// Save User to Database
|
// Save User to Database
|
||||||
User.create({
|
Auth.create({
|
||||||
firstName: req.body.firstName,
|
|
||||||
lastName: req.body.lastName,
|
|
||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
dateOfBirth: new Date(req.body.dateOfBirth),
|
|
||||||
password: req.body.password
|
password: req.body.password
|
||||||
})
|
}).then((auth) => {
|
||||||
.then(user => {
|
User.create({
|
||||||
if (req.body.roles) {
|
firstName: req.body.firstName,
|
||||||
Role.findAll({
|
lastName: req.body.lastName,
|
||||||
where: {
|
dateOfBirth: new Date(req.body.dateOfBirth),
|
||||||
name: {
|
authId: auth.id,
|
||||||
[Op.or]: req.body.roles
|
gender: 'male',
|
||||||
}
|
handedness: 'right'
|
||||||
}
|
}).then(user => {
|
||||||
}).then(roles => {
|
if (!req.body.roles || !req.body.roles.length === 0) {
|
||||||
user.setRoles(roles).then(() => {
|
req.body.roles = ['player'];
|
||||||
res.send({ message: "User registered successfully!" });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// user role = 1
|
|
||||||
user.setRoles([1]).then(() => {
|
|
||||||
res.send({ message: "User registered successfully!" });
|
|
||||||
}, (error) => {
|
|
||||||
console.log(JSON.stringify(error, null, 2));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
})
|
Role.findAll({
|
||||||
.catch(err => {
|
where: {
|
||||||
|
name: {
|
||||||
|
[Op.or]: req.body.roles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).then(roles => {
|
||||||
|
user.setRoles(roles).then(() => {
|
||||||
|
res.send({ message: "User registered successfully!" });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
res.status(500).send({ message: err.message });
|
res.status(500).send({ message: err.message });
|
||||||
});
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
res.status(500).send({ message: err.message });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.login = (req, res) => {
|
exports.login = (req, res) => {
|
||||||
User.findOne({
|
Auth.findOne({
|
||||||
where: {
|
where: {
|
||||||
email: req.body.email
|
email: req.body.email
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(async (user) => {
|
.then(async (auth) => {
|
||||||
if (!user) {
|
if (!auth) {
|
||||||
return res.status(404).send({ message: "User Not found." });
|
return res.status(404).send({ message: "User Not found." });
|
||||||
}
|
}
|
||||||
|
|
||||||
const passwordIsValid = user.validPassword(req.body.password);
|
await User.findOne({
|
||||||
|
where: {
|
||||||
if (!passwordIsValid) {
|
authId: auth.id
|
||||||
return res.status(401).send({
|
|
||||||
accessToken: null,
|
|
||||||
message: "Invalid Password!"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const token = jwt.sign({ id: user.id },
|
|
||||||
config.secret,
|
|
||||||
{
|
|
||||||
algorithm: 'HS256',
|
|
||||||
allowInsecureKeySizes: true,
|
|
||||||
expiresIn: config.jwtExpiration
|
|
||||||
});
|
|
||||||
|
|
||||||
let refreshToken = await RefreshToken.createToken(user);
|
|
||||||
|
|
||||||
const authorities = [];
|
|
||||||
user.getRoles().then(roles => {
|
|
||||||
for (let i = 0; i < roles.length; i++) {
|
|
||||||
authorities.push("ROLE_" + roles[i].name.toUpperCase());
|
|
||||||
}
|
}
|
||||||
res.status(200).send({
|
}).then(async (user) => {
|
||||||
id: user.id,
|
const passwordIsValid = auth.validPassword(req.body.password);
|
||||||
username: user.username,
|
|
||||||
email: user.email,
|
if (!passwordIsValid) {
|
||||||
roles: authorities,
|
return res.status(401).send({
|
||||||
accessToken: token,
|
accessToken: null,
|
||||||
refreshToken: refreshToken
|
message: "Invalid Password!"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = jwt.sign({ id: auth.id },
|
||||||
|
config.secret,
|
||||||
|
{
|
||||||
|
algorithm: 'HS256',
|
||||||
|
allowInsecureKeySizes: true,
|
||||||
|
expiresIn: config.jwtExpiration
|
||||||
|
});
|
||||||
|
|
||||||
|
let refreshToken = await RefreshToken.createToken(auth);
|
||||||
|
|
||||||
|
const authorities = [];
|
||||||
|
user.getRoles().then(roles => {
|
||||||
|
for (let i = 0; i < roles.length; i++) {
|
||||||
|
authorities.push("ROLE_" + roles[i].name.toUpperCase());
|
||||||
|
}
|
||||||
|
res.status(200).send({
|
||||||
|
id: user.id,
|
||||||
|
email: auth.email,
|
||||||
|
roles: authorities,
|
||||||
|
accessToken: token,
|
||||||
|
refreshToken: refreshToken
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
res.status(500).send({ message: err.message });
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
|
@ -92,9 +99,9 @@ exports.login = (req, res) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.logout = (req, res) => {
|
// exports.logout = (req, res) => {
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
exports.refreshToken = async (req, res) => {
|
exports.refreshToken = async (req, res) => {
|
||||||
const { refreshToken: requestToken } = req.body;
|
const { refreshToken: requestToken } = req.body;
|
||||||
|
|
@ -122,8 +129,7 @@ exports.refreshToken = async (req, res) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await refreshToken.getUser();
|
let newAccessToken = jwt.sign({ id: auth.id }, config.secret, {
|
||||||
let newAccessToken = jwt.sign({ id: user.id }, config.secret, {
|
|
||||||
expiresIn: config.jwtExpiration,
|
expiresIn: config.jwtExpiration,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
const db = require("../models/index");
|
const db = require("../models/index");
|
||||||
const User = db.User;
|
const Auth = db.Auth;
|
||||||
|
|
||||||
checkDuplicateUsernameOrEmail = (req, res, next) => {
|
checkDuplicateUsernameOrEmail = (req, res, next) => {
|
||||||
// Username
|
// Username
|
||||||
User.findOne({
|
Auth.findOne({
|
||||||
where: {
|
where: {
|
||||||
email: req.body.email
|
email: req.body.email
|
||||||
}
|
}
|
||||||
}).then(user => {
|
}).then(auth => {
|
||||||
if (user) {
|
if (auth) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
message: "Failed! Email is already in use!"
|
message: "Failed! Email is already in use!"
|
||||||
});
|
});
|
||||||
|
|
@ -21,6 +21,7 @@ checkDuplicateUsernameOrEmail = (req, res, next) => {
|
||||||
|
|
||||||
checkRolesExisted = (req, res, next) => {
|
checkRolesExisted = (req, res, next) => {
|
||||||
if (req.body.roles) {
|
if (req.body.roles) {
|
||||||
|
const ROLES = ['player', 'coach', 'admin'];
|
||||||
for (let i = 0; i < req.body.roles.length; i++) {
|
for (let i = 0; i < req.body.roles.length; i++) {
|
||||||
if (!ROLES.includes(req.body.roles[i])) {
|
if (!ROLES.includes(req.body.roles[i])) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/** @type {import('sequelize-cli').Migration} */
|
||||||
|
module.exports = {
|
||||||
|
async up(queryInterface, Sequelize) {
|
||||||
|
await queryInterface.createTable('Authentications', {
|
||||||
|
id: {
|
||||||
|
allowNull: false,
|
||||||
|
autoIncrement: true,
|
||||||
|
primaryKey: true,
|
||||||
|
type: Sequelize.INTEGER
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: Sequelize.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: true,
|
||||||
|
validate: {isEmail: true},
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: Sequelize.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
createdAt: {
|
||||||
|
allowNull: false,
|
||||||
|
type: Sequelize.DATE
|
||||||
|
},
|
||||||
|
updatedAt: {
|
||||||
|
allowNull: false,
|
||||||
|
type: Sequelize.DATE
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async down(queryInterface, /*Sequelize*/) {
|
||||||
|
await queryInterface.dropTable('Authentications');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
'use strict';
|
|
||||||
/** @type {import('sequelize-cli').Migration} */
|
/** @type {import('sequelize-cli').Migration} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
async up(queryInterface, Sequelize) {
|
async up(queryInterface, Sequelize) {
|
||||||
|
|
@ -9,6 +8,15 @@ module.exports = {
|
||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
type: Sequelize.INTEGER
|
type: Sequelize.INTEGER
|
||||||
},
|
},
|
||||||
|
authId: {
|
||||||
|
type: Sequelize.INTEGER,
|
||||||
|
references: {
|
||||||
|
model: 'Authentications',
|
||||||
|
key: 'id'
|
||||||
|
},
|
||||||
|
onUpdate: 'CASCADE',
|
||||||
|
onDelete: 'CASCADE'
|
||||||
|
},
|
||||||
firstName: {
|
firstName: {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
type: Sequelize.STRING
|
type: Sequelize.STRING
|
||||||
|
|
@ -17,18 +25,29 @@ module.exports = {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
type: Sequelize.STRING
|
type: Sequelize.STRING
|
||||||
},
|
},
|
||||||
email: {
|
|
||||||
allowNull: false,
|
|
||||||
type: Sequelize.STRING
|
|
||||||
},
|
|
||||||
dateOfBirth: {
|
dateOfBirth: {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
type: Sequelize.DATE
|
type: Sequelize.DATE
|
||||||
},
|
},
|
||||||
password: {
|
height: {
|
||||||
allowNull: false,
|
type: Sequelize.FLOAT
|
||||||
type: Sequelize.STRING
|
|
||||||
},
|
},
|
||||||
|
weight: {
|
||||||
|
type: Sequelize.FLOAT
|
||||||
|
},
|
||||||
|
gender: {
|
||||||
|
allowNull: false,
|
||||||
|
type: Sequelize.ENUM('male', 'female', 'other'),
|
||||||
|
},
|
||||||
|
handedness: {
|
||||||
|
type: Sequelize.ENUM('left', 'right', 'both'),
|
||||||
|
},
|
||||||
|
// position: {
|
||||||
|
// type: DataTypes.ENUM
|
||||||
|
// },
|
||||||
|
// preferredPosition: {
|
||||||
|
// type: DataTypes.ENUM
|
||||||
|
// }
|
||||||
createdAt: {
|
createdAt: {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
type: Sequelize.DATE
|
type: Sequelize.DATE
|
||||||
|
|
@ -39,7 +58,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async down(queryInterface, Sequelize) {
|
async down(queryInterface, /*Sequelize*/) {
|
||||||
await queryInterface.dropTable('Users');
|
await queryInterface.dropTable('Users');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -12,10 +12,10 @@ module.exports = {
|
||||||
token: {
|
token: {
|
||||||
type: Sequelize.STRING
|
type: Sequelize.STRING
|
||||||
},
|
},
|
||||||
userId: {
|
authId: {
|
||||||
type: Sequelize.INTEGER,
|
type: Sequelize.INTEGER,
|
||||||
references: {
|
references: {
|
||||||
model: 'Users',
|
model: 'Authentications',
|
||||||
key: 'id'
|
key: 'id'
|
||||||
},
|
},
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
|
|
@ -34,7 +34,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async down(queryInterface, Sequelize) {
|
async down(queryInterface, /*Sequelize*/) {
|
||||||
await queryInterface.dropTable('RefreshTokens');
|
await queryInterface.dropTable('RefreshTokens');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
const { Model } = require('sequelize');
|
||||||
|
const bcrypt = require("bcryptjs");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
class Auth extends Model {
|
||||||
|
/**
|
||||||
|
* Helper method for defining associations.
|
||||||
|
* This method is not a part of Sequelize lifecycle.
|
||||||
|
* The `models/index` file will call this method automatically.
|
||||||
|
*/
|
||||||
|
static associate(models) {
|
||||||
|
Auth.hasOne(models.User, {
|
||||||
|
foreignKey: 'authId',
|
||||||
|
as: 'user'
|
||||||
|
});
|
||||||
|
Auth.hasMany(models.RefreshToken, {
|
||||||
|
foreignKey: 'authId',
|
||||||
|
as: 'tokens'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth.init({
|
||||||
|
email: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: true,
|
||||||
|
validate: {isEmail: true},
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: 'Auth',
|
||||||
|
tableName: 'Authentications',
|
||||||
|
timestamps: true,
|
||||||
|
hooks: {
|
||||||
|
beforeCreate: async (auth) => {
|
||||||
|
const salt = await bcrypt.genSalt(10);
|
||||||
|
auth.password = await bcrypt.hash(auth.password, salt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
defaultScope: {
|
||||||
|
attributes: { exclude: ['password'] },
|
||||||
|
},
|
||||||
|
scopes: {
|
||||||
|
withSecretColumns: {
|
||||||
|
attributes: { include: ['password'] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Auth.prototype.validPassword = function (password) {
|
||||||
|
return bcrypt.compareSync(password, this.password);
|
||||||
|
};
|
||||||
|
|
||||||
|
return Auth;
|
||||||
|
}
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
const { Model } = require('sequelize');
|
|
||||||
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
class Member extends Model {
|
|
||||||
/**
|
|
||||||
* Helper method for defining associations.
|
|
||||||
* This method is not a part of Sequelize lifecycle.
|
|
||||||
* The `models/index` file will call this method automatically.
|
|
||||||
*/
|
|
||||||
static associate(models) {
|
|
||||||
// Member.belongsTo(models.User, {
|
|
||||||
// foreignKey: 'loginId',
|
|
||||||
// targetKey: 'id'
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Member.init({
|
|
||||||
firstName: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
lastName: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
dateOfBirth: {
|
|
||||||
type: DataTypes.DATE,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: DataTypes.INTEGER
|
|
||||||
},
|
|
||||||
weight: {
|
|
||||||
type: DataTypes.INTEGER
|
|
||||||
},
|
|
||||||
// handedness: {
|
|
||||||
// type: DataTypes.ENUM('LeftHandedness', 'RightHandedness'),
|
|
||||||
// },
|
|
||||||
// position: {
|
|
||||||
// type: DataTypes.ENUM
|
|
||||||
// },
|
|
||||||
// preferredPosition: {
|
|
||||||
// type: DataTypes.ENUM
|
|
||||||
// }
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'Member',
|
|
||||||
tableName: "Members"
|
|
||||||
});
|
|
||||||
|
|
||||||
return Member;
|
|
||||||
};
|
|
||||||
|
|
@ -10,8 +10,8 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
* The `models/index` file will call this method automatically.
|
* The `models/index` file will call this method automatically.
|
||||||
*/
|
*/
|
||||||
static associate(models) {
|
static associate(models) {
|
||||||
RefreshToken.belongsTo(models.User, {
|
RefreshToken.belongsTo(models.Auth, {
|
||||||
foreignKey: 'userId',
|
foreignKey: 'authId',
|
||||||
targetKey: 'id'
|
targetKey: 'id'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +31,7 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
tableName: 'RefreshTokens'
|
tableName: 'RefreshTokens'
|
||||||
});
|
});
|
||||||
|
|
||||||
RefreshToken.createToken = async function (user) {
|
RefreshToken.createToken = async function (auth) {
|
||||||
let expiredAt = new Date();
|
let expiredAt = new Date();
|
||||||
|
|
||||||
expiredAt.setSeconds(expiredAt.getSeconds() + config.jwtRefreshExpiration);
|
expiredAt.setSeconds(expiredAt.getSeconds() + config.jwtRefreshExpiration);
|
||||||
|
|
@ -40,7 +40,7 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
|
|
||||||
let refreshToken = await this.create({
|
let refreshToken = await this.create({
|
||||||
token: _token,
|
token: _token,
|
||||||
userId: user.id,
|
authId: auth.id,
|
||||||
expiryDate: expiredAt.getTime(),
|
expiryDate: expiredAt.getTime(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
const { Model } = require('sequelize');
|
const { Model } = require('sequelize');
|
||||||
const bcrypt = require("bcryptjs");
|
|
||||||
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
module.exports = (sequelize, DataTypes) => {
|
||||||
class User extends Model {
|
class User extends Model {
|
||||||
|
|
@ -14,9 +13,9 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
foreignKey: 'userId',
|
foreignKey: 'userId',
|
||||||
as: 'roles',
|
as: 'roles',
|
||||||
});
|
});
|
||||||
User.hasOne(models.RefreshToken, {
|
User.belongsTo(models.Auth, {
|
||||||
foreignKey: 'userId',
|
foreignKey: 'authId',
|
||||||
targetKey: 'id'
|
as: 'auth'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -30,42 +29,33 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
dateOfBirth: {
|
dateOfBirth: {
|
||||||
type: DataTypes.DATE,
|
type: DataTypes.DATEONLY,
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
email: {
|
height: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.FLOAT
|
||||||
allowNull: false,
|
|
||||||
unique: true
|
|
||||||
},
|
},
|
||||||
password: {
|
weight: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.FLOAT
|
||||||
|
},
|
||||||
|
gender: {
|
||||||
|
type: DataTypes.ENUM('male', 'female', 'other'),
|
||||||
allowNull: false
|
allowNull: false
|
||||||
}
|
},
|
||||||
|
handedness: {
|
||||||
|
type: DataTypes.ENUM('left', 'right', 'both'),
|
||||||
|
},
|
||||||
|
// position: {
|
||||||
|
// type: DataTypes.ENUM
|
||||||
|
// },
|
||||||
|
// preferredPosition: {
|
||||||
|
// type: DataTypes.ENUM
|
||||||
|
// }
|
||||||
}, {
|
}, {
|
||||||
sequelize,
|
sequelize,
|
||||||
modelName: 'User',
|
modelName: 'User',
|
||||||
tableName: "Users",
|
tableName: "Users"
|
||||||
hooks: {
|
|
||||||
beforeCreate: async (user) => {
|
|
||||||
const salt = await bcrypt.genSalt(10);
|
|
||||||
user.password = await bcrypt.hash(user.password, salt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
defaultScope: {
|
|
||||||
attributes: { exclude: ['password'] },
|
|
||||||
},
|
|
||||||
scopes: {
|
|
||||||
withSecretColumns: {
|
|
||||||
attributes: { include: ['password'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
User.prototype.validPassword = function (password) {
|
|
||||||
return bcrypt.compareSync(password, this.password);
|
|
||||||
};
|
|
||||||
|
|
||||||
return User;
|
return User;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,14 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** @type {import('sequelize-cli').Migration} */
|
/** @type {import('sequelize-cli').Migration} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
async up (queryInterface, Sequelize) {
|
async up (queryInterface, /*Sequelize*/) {
|
||||||
return queryInterface.bulkInsert('Roles', [{
|
return queryInterface.bulkInsert('Roles', [
|
||||||
id: 1,
|
{ name: 'player', createdAt: new Date(), updatedAt: new Date() },
|
||||||
name: 'user',
|
{ name: 'coach', createdAt: new Date(), updatedAt: new Date() },
|
||||||
createdAt: new Date(),
|
{ name: 'admin', createdAt: new Date(), updatedAt: new Date() }
|
||||||
updatedAt: new Date(),
|
]);
|
||||||
}, {
|
|
||||||
id: 2,
|
|
||||||
name: 'administrator',
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
}]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async down (queryInterface, Sequelize) {
|
async down (queryInterface, /*Sequelize*/) {
|
||||||
return queryInterface.dropTable('Roles');
|
return queryInterface.dropTable('Roles');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,69 @@ const bcrypt = require("bcryptjs");
|
||||||
|
|
||||||
/** @type {import('sequelize-cli').Migration} */
|
/** @type {import('sequelize-cli').Migration} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
async up (queryInterface, Sequelize) {
|
async up (queryInterface, /*Sequelize*/) {
|
||||||
return queryInterface.bulkInsert('Users', [{
|
await queryInterface.bulkInsert('Authentications', [
|
||||||
firstName: 'Nolan',
|
{ email: 'player@example.com', password: bcrypt.hashSync('hash1234', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||||
lastName: 'Ryan',
|
{ email: 'coach@example.com', password: bcrypt.hashSync('hash2345', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||||
dateOfBirth: new Date(1947, 1, 31),
|
{ email: 'admin@example.com', password: bcrypt.hashSync('hash3456', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||||
email: 'ryan.nolan@bullpen.com',
|
]);
|
||||||
password: bcrypt.hashSync('nolan', 8),
|
|
||||||
createdAt: new Date(),
|
const auths = await queryInterface.select(null, 'Authentications');
|
||||||
updatedAt: new Date(),
|
const playerAuthId = auths.filter((auth) => auth.email === 'player@example.com').map((auth) => auth.id).shift();
|
||||||
}]);
|
const coachAuthId = auths.filter((auth) => auth.email === 'coach@example.com').map((auth) => auth.id).shift();
|
||||||
|
const adminAuthId = auths.filter((auth) => auth.email === 'admin@example.com').map((auth) => auth.id).shift();
|
||||||
|
|
||||||
|
await queryInterface.bulkInsert('Users', [{
|
||||||
|
firstName: 'Alice',
|
||||||
|
lastName: 'Player',
|
||||||
|
dateOfBirth: '1990-01-01',
|
||||||
|
gender: 'female',
|
||||||
|
handedness: 'right',
|
||||||
|
authId: playerAuthId,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
}, {
|
||||||
|
firstName: 'Bob',
|
||||||
|
lastName: 'Coach',
|
||||||
|
dateOfBirth: '1985-05-05',
|
||||||
|
gender: 'male',
|
||||||
|
handedness: 'left',
|
||||||
|
authId: coachAuthId,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
}, {
|
||||||
|
firstName: 'Charlie',
|
||||||
|
lastName: 'Admin',
|
||||||
|
dateOfBirth: '1980-03-03',
|
||||||
|
gender: 'other',
|
||||||
|
handedness: 'both',
|
||||||
|
authId: adminAuthId,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
|
||||||
|
const users = await queryInterface.select(null, 'Users');
|
||||||
|
const aliceId = users.filter((user) => user.firstName === 'Alice').map((user) => user.id).shift();
|
||||||
|
const bobId = users.filter((user) => user.firstName === 'Bob').map((user) => user.id).shift();
|
||||||
|
const charlieId = users.filter((user) => user.firstName === 'Charlie').map((user) => user.id).shift();
|
||||||
|
|
||||||
|
const roles = await queryInterface.select(null, 'Roles');
|
||||||
|
const playerId = roles.filter((role) => role.name === 'player').map((role) => role.id).shift();
|
||||||
|
const coachId = roles.filter((role) => role.name === 'coach').map((role) => role.id).shift();
|
||||||
|
const adminId = roles.filter((role) => role.name === 'admin').map((role) => role.id).shift();
|
||||||
|
|
||||||
|
await queryInterface.bulkInsert('UserRoles', [
|
||||||
|
{ userId: aliceId, roleId: playerId, createdAt: new Date(), updatedAt: new Date() },
|
||||||
|
{ userId: bobId, roleId: coachId, createdAt: new Date(), updatedAt: new Date() },
|
||||||
|
{ userId: charlieId, roleId: adminId, createdAt: new Date(), updatedAt: new Date() },
|
||||||
|
]);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async down (queryInterface, Sequelize) {
|
async down (queryInterface, /*Sequelize*/) {
|
||||||
return queryInterface.dropTable('Users');
|
await queryInterface.dropTable('Authentications');
|
||||||
|
await queryInterface.dropTable('Users');
|
||||||
|
await queryInterface.dropTable('UserRoles');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ describe("Test bullpen session", () => {
|
||||||
let response = await request(app)
|
let response = await request(app)
|
||||||
.post("/api/auth/login")
|
.post("/api/auth/login")
|
||||||
.send({
|
.send({
|
||||||
email: 'ryan.nolan@bullpen.com',
|
email: 'player@example.com',
|
||||||
password: 'nolan'
|
password: 'hash1234'
|
||||||
});
|
});
|
||||||
const user = response.body;
|
const user = response.body;
|
||||||
|
|
||||||
|
|
@ -38,6 +38,6 @@ describe("Test bullpen session", () => {
|
||||||
.set('x-access-token', user.accessToken);
|
.set('x-access-token', user.accessToken);
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
console.log(JSON.stringify(response.body, null, 2));
|
// console.log(JSON.stringify(response.body, null, 2));
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ const signupUser = {
|
||||||
lastName: "Zimmer",
|
lastName: "Zimmer",
|
||||||
dateOfBirth: "1956-11-23",
|
dateOfBirth: "1956-11-23",
|
||||||
email: "hans.zimmer@email.com",
|
email: "hans.zimmer@email.com",
|
||||||
password: "secret123"
|
password: "secret123",
|
||||||
|
roles: ['admin']
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ describe("Test retrieving pitch types", () => {
|
||||||
let response = await request(app)
|
let response = await request(app)
|
||||||
.post("/api/auth/login")
|
.post("/api/auth/login")
|
||||||
.send({
|
.send({
|
||||||
email: 'ryan.nolan@bullpen.com',
|
email: 'player@example.com',
|
||||||
password: 'nolan'
|
password: 'hash1234'
|
||||||
});
|
});
|
||||||
const user = response.body;
|
const user = response.body;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ describe("Test user authentication", () => {
|
||||||
let response = await request(app)
|
let response = await request(app)
|
||||||
.post("/api/auth/login")
|
.post("/api/auth/login")
|
||||||
.send({
|
.send({
|
||||||
email: 'ryan.nolan@bullpen.com',
|
email: signupUser.email,
|
||||||
password: 'nolan'
|
password: signupUser.password,
|
||||||
});
|
});
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body.accessToken).not.toBeNull();
|
expect(response.body.accessToken).not.toBeNull();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue