restructured user, auth, role models
This commit is contained in:
parent
26edfd46fe
commit
69427f1809
|
|
@ -1,2 +1,3 @@
|
|||
.idea/
|
||||
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 cors = require("cors");
|
||||
const bcrypt = require("bcryptjs");
|
||||
|
||||
const app = express();
|
||||
|
||||
|
|
@ -14,13 +13,7 @@ app.use(express.json());
|
|||
// parse requests of content-type - application/x-www-form-urlencoded
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// database
|
||||
const db = require("./models");
|
||||
const Role = db.Role;
|
||||
const User = db.User;
|
||||
const PitchType = db.PitchType;
|
||||
|
||||
db.sequelize.sync();
|
||||
// db.sequelize.sync();
|
||||
// force: true will drop the table if it already exists
|
||||
// db.sequelize.sync({force: true}).then(() => {
|
||||
// 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/bullpenSession.routes')(app);
|
||||
|
||||
function initial() {
|
||||
Role.bulkCreate([
|
||||
{ name: 'user' },
|
||||
{ name: 'administrator' },
|
||||
]);
|
||||
User.bulkCreate([
|
||||
{ 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: '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) }
|
||||
]);
|
||||
|
||||
User.findAll().then(users => {
|
||||
users.forEach(user => {
|
||||
user.setRoles([1]);
|
||||
});
|
||||
});
|
||||
|
||||
PitchType.bulkCreate([
|
||||
{ name: 'Fastball', abbreviation: 'FB' },
|
||||
{ name: 'Curveball', abbreviation: 'CB' },
|
||||
{ name: 'Slider', abbreviation: 'SL' },
|
||||
{ name: 'Changeup', abbreviation: 'CH' },
|
||||
{ name: 'Cutter', abbreviation: 'CUT' },
|
||||
{ name: 'Sweeper', abbreviation: 'SW' },
|
||||
{ name: 'Slurve', abbreviation: 'SLV' },
|
||||
]);
|
||||
}
|
||||
// function initial() {
|
||||
// Role.bulkCreate([
|
||||
// { name: 'user' },
|
||||
// { name: 'administrator' },
|
||||
// ]);
|
||||
// User.bulkCreate([
|
||||
// { 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: '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) }
|
||||
// ]);
|
||||
//
|
||||
// User.findAll().then(users => {
|
||||
// users.forEach(user => {
|
||||
// user.setRoles([1]);
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// PitchType.bulkCreate([
|
||||
// { name: 'Fastball', abbreviation: 'FB' },
|
||||
// { name: 'Curveball', abbreviation: 'CB' },
|
||||
// { name: 'Slider', abbreviation: 'SL' },
|
||||
// { name: 'Changeup', abbreviation: 'CH' },
|
||||
// { name: 'Cutter', abbreviation: 'CUT' },
|
||||
// { name: 'Sweeper', abbreviation: 'SW' },
|
||||
// { name: 'Slurve', abbreviation: 'SLV' },
|
||||
// ]);
|
||||
// }
|
||||
|
||||
module.exports = app;
|
||||
|
|
|
|||
|
|
@ -1,38 +1,31 @@
|
|||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
development: {
|
||||
dialect: 'postgres',
|
||||
username: 'tester',
|
||||
password: 'test123',
|
||||
database: 'bullpen',
|
||||
host: 'localhost',
|
||||
port: 15432,
|
||||
logging: false,
|
||||
},
|
||||
test: {
|
||||
dialect: 'postgres',
|
||||
username: 'test',
|
||||
password: 'test123!',
|
||||
database: 'bullpen',
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
username: process.env.DB_TEST_USER,
|
||||
password: process.env.DB_TEST_PASSWORD,
|
||||
database: process.env.DB_TEST_NAME,
|
||||
host: process.env.DB_TEST_HOST,
|
||||
port: process.env.DB_TEST_PORT,
|
||||
dialect: process.env.DB_TEST_DIALECT,
|
||||
logging: false,
|
||||
},
|
||||
staging: {
|
||||
username: process.env.DB_USER,
|
||||
password: process.env.DB_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
host: process.env.DB_HOST,
|
||||
dialect: process.env.DB_DIALECT,
|
||||
development: {
|
||||
username: process.env.DB_DEV_USER,
|
||||
password: process.env.DB_DEV_PASSWORD,
|
||||
database: process.env.DB_DEV_NAME,
|
||||
host: process.env.DB_DEV_HOST,
|
||||
port: process.env.DB_DEV_PORT,
|
||||
dialect: process.env.DB_DEV_DIALECT,
|
||||
logging: false,
|
||||
},
|
||||
production: {
|
||||
username: process.env.DB_USER,
|
||||
password: process.env.DB_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
host: process.env.DB_HOST,
|
||||
dialect: process.env.DB_DIALECT,
|
||||
username: process.env.DB_PROD_USER,
|
||||
password: process.env.DB_PROD_PASSWORD,
|
||||
database: process.env.DB_PROD_NAME,
|
||||
host: process.env.DB_PROD_HOST,
|
||||
port: process.env.DB_PROD_PORT,
|
||||
dialect: process.env.DB_PROD_DIALECT,
|
||||
logging: false,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const db = require("../models/index");
|
||||
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;
|
||||
|
||||
|
|
@ -8,83 +8,90 @@ const jwt = require("jsonwebtoken");
|
|||
|
||||
exports.register = (req, res) => {
|
||||
// Save User to Database
|
||||
User.create({
|
||||
firstName: req.body.firstName,
|
||||
lastName: req.body.lastName,
|
||||
Auth.create({
|
||||
email: req.body.email,
|
||||
dateOfBirth: new Date(req.body.dateOfBirth),
|
||||
password: req.body.password
|
||||
})
|
||||
.then(user => {
|
||||
if (req.body.roles) {
|
||||
Role.findAll({
|
||||
where: {
|
||||
name: {
|
||||
[Op.or]: req.body.roles
|
||||
}
|
||||
}
|
||||
}).then(roles => {
|
||||
user.setRoles(roles).then(() => {
|
||||
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));
|
||||
});
|
||||
}).then((auth) => {
|
||||
User.create({
|
||||
firstName: req.body.firstName,
|
||||
lastName: req.body.lastName,
|
||||
dateOfBirth: new Date(req.body.dateOfBirth),
|
||||
authId: auth.id,
|
||||
gender: 'male',
|
||||
handedness: 'right'
|
||||
}).then(user => {
|
||||
if (!req.body.roles || !req.body.roles.length === 0) {
|
||||
req.body.roles = ['player'];
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
Role.findAll({
|
||||
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 });
|
||||
});
|
||||
}).catch(err => {
|
||||
res.status(500).send({ message: err.message });
|
||||
});
|
||||
};
|
||||
|
||||
exports.login = (req, res) => {
|
||||
User.findOne({
|
||||
Auth.findOne({
|
||||
where: {
|
||||
email: req.body.email
|
||||
}
|
||||
})
|
||||
.then(async (user) => {
|
||||
if (!user) {
|
||||
.then(async (auth) => {
|
||||
if (!auth) {
|
||||
return res.status(404).send({ message: "User Not found." });
|
||||
}
|
||||
|
||||
const passwordIsValid = user.validPassword(req.body.password);
|
||||
|
||||
if (!passwordIsValid) {
|
||||
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());
|
||||
await User.findOne({
|
||||
where: {
|
||||
authId: auth.id
|
||||
}
|
||||
res.status(200).send({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
roles: authorities,
|
||||
accessToken: token,
|
||||
refreshToken: refreshToken
|
||||
}).then(async (user) => {
|
||||
const passwordIsValid = auth.validPassword(req.body.password);
|
||||
|
||||
if (!passwordIsValid) {
|
||||
return res.status(401).send({
|
||||
accessToken: null,
|
||||
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 => {
|
||||
|
|
@ -92,9 +99,9 @@ exports.login = (req, res) => {
|
|||
});
|
||||
};
|
||||
|
||||
exports.logout = (req, res) => {
|
||||
|
||||
}
|
||||
// exports.logout = (req, res) => {
|
||||
//
|
||||
// }
|
||||
|
||||
exports.refreshToken = async (req, res) => {
|
||||
const { refreshToken: requestToken } = req.body;
|
||||
|
|
@ -122,8 +129,7 @@ exports.refreshToken = async (req, res) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const user = await refreshToken.getUser();
|
||||
let newAccessToken = jwt.sign({ id: user.id }, config.secret, {
|
||||
let newAccessToken = jwt.sign({ id: auth.id }, config.secret, {
|
||||
expiresIn: config.jwtExpiration,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
const db = require("../models/index");
|
||||
const User = db.User;
|
||||
const Auth = db.Auth;
|
||||
|
||||
checkDuplicateUsernameOrEmail = (req, res, next) => {
|
||||
// Username
|
||||
User.findOne({
|
||||
Auth.findOne({
|
||||
where: {
|
||||
email: req.body.email
|
||||
}
|
||||
}).then(user => {
|
||||
if (user) {
|
||||
}).then(auth => {
|
||||
if (auth) {
|
||||
res.status(400).send({
|
||||
message: "Failed! Email is already in use!"
|
||||
});
|
||||
|
|
@ -21,6 +21,7 @@ checkDuplicateUsernameOrEmail = (req, res, next) => {
|
|||
|
||||
checkRolesExisted = (req, res, next) => {
|
||||
if (req.body.roles) {
|
||||
const ROLES = ['player', 'coach', 'admin'];
|
||||
for (let i = 0; i < req.body.roles.length; i++) {
|
||||
if (!ROLES.includes(req.body.roles[i])) {
|
||||
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} */
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
|
|
@ -9,6 +8,15 @@ module.exports = {
|
|||
primaryKey: true,
|
||||
type: Sequelize.INTEGER
|
||||
},
|
||||
authId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Authentications',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'CASCADE',
|
||||
onDelete: 'CASCADE'
|
||||
},
|
||||
firstName: {
|
||||
allowNull: false,
|
||||
type: Sequelize.STRING
|
||||
|
|
@ -17,18 +25,29 @@ module.exports = {
|
|||
allowNull: false,
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
email: {
|
||||
allowNull: false,
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
dateOfBirth: {
|
||||
allowNull: false,
|
||||
type: Sequelize.DATE
|
||||
},
|
||||
password: {
|
||||
allowNull: false,
|
||||
type: Sequelize.STRING
|
||||
height: {
|
||||
type: Sequelize.FLOAT
|
||||
},
|
||||
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: {
|
||||
allowNull: false,
|
||||
type: Sequelize.DATE
|
||||
|
|
@ -39,7 +58,7 @@ module.exports = {
|
|||
}
|
||||
});
|
||||
},
|
||||
async down(queryInterface, Sequelize) {
|
||||
async down(queryInterface, /*Sequelize*/) {
|
||||
await queryInterface.dropTable('Users');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ module.exports = {
|
|||
token: {
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
userId: {
|
||||
authId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Users',
|
||||
model: 'Authentications',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'CASCADE',
|
||||
|
|
@ -34,7 +34,7 @@ module.exports = {
|
|||
}
|
||||
});
|
||||
},
|
||||
async down(queryInterface, Sequelize) {
|
||||
async down(queryInterface, /*Sequelize*/) {
|
||||
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.
|
||||
*/
|
||||
static associate(models) {
|
||||
RefreshToken.belongsTo(models.User, {
|
||||
foreignKey: 'userId',
|
||||
RefreshToken.belongsTo(models.Auth, {
|
||||
foreignKey: 'authId',
|
||||
targetKey: 'id'
|
||||
});
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ module.exports = (sequelize, DataTypes) => {
|
|||
tableName: 'RefreshTokens'
|
||||
});
|
||||
|
||||
RefreshToken.createToken = async function (user) {
|
||||
RefreshToken.createToken = async function (auth) {
|
||||
let expiredAt = new Date();
|
||||
|
||||
expiredAt.setSeconds(expiredAt.getSeconds() + config.jwtRefreshExpiration);
|
||||
|
|
@ -40,7 +40,7 @@ module.exports = (sequelize, DataTypes) => {
|
|||
|
||||
let refreshToken = await this.create({
|
||||
token: _token,
|
||||
userId: user.id,
|
||||
authId: auth.id,
|
||||
expiryDate: expiredAt.getTime(),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
const { Model } = require('sequelize');
|
||||
const bcrypt = require("bcryptjs");
|
||||
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
class User extends Model {
|
||||
|
|
@ -14,9 +13,9 @@ module.exports = (sequelize, DataTypes) => {
|
|||
foreignKey: 'userId',
|
||||
as: 'roles',
|
||||
});
|
||||
User.hasOne(models.RefreshToken, {
|
||||
foreignKey: 'userId',
|
||||
targetKey: 'id'
|
||||
User.belongsTo(models.Auth, {
|
||||
foreignKey: 'authId',
|
||||
as: 'auth'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -30,42 +29,33 @@ module.exports = (sequelize, DataTypes) => {
|
|||
allowNull: false
|
||||
},
|
||||
dateOfBirth: {
|
||||
type: DataTypes.DATE,
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false
|
||||
},
|
||||
email: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true
|
||||
height: {
|
||||
type: DataTypes.FLOAT
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING,
|
||||
weight: {
|
||||
type: DataTypes.FLOAT
|
||||
},
|
||||
gender: {
|
||||
type: DataTypes.ENUM('male', 'female', 'other'),
|
||||
allowNull: false
|
||||
}
|
||||
},
|
||||
handedness: {
|
||||
type: DataTypes.ENUM('left', 'right', 'both'),
|
||||
},
|
||||
// position: {
|
||||
// type: DataTypes.ENUM
|
||||
// },
|
||||
// preferredPosition: {
|
||||
// type: DataTypes.ENUM
|
||||
// }
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'User',
|
||||
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'] },
|
||||
},
|
||||
},
|
||||
tableName: "Users"
|
||||
});
|
||||
|
||||
User.prototype.validPassword = function (password) {
|
||||
return bcrypt.compareSync(password, this.password);
|
||||
};
|
||||
|
||||
return User;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,22 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
/** @type {import('sequelize-cli').Migration} */
|
||||
module.exports = {
|
||||
async up (queryInterface, Sequelize) {
|
||||
return queryInterface.bulkInsert('Roles', [{
|
||||
id: 1,
|
||||
name: 'user',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'administrator',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}]);
|
||||
async up (queryInterface, /*Sequelize*/) {
|
||||
return queryInterface.bulkInsert('Roles', [
|
||||
{ name: 'player', createdAt: new Date(), updatedAt: new Date() },
|
||||
{ name: 'coach', createdAt: new Date(), updatedAt: new Date() },
|
||||
{ name: 'admin', createdAt: new Date(), updatedAt: new Date() }
|
||||
]);
|
||||
},
|
||||
|
||||
async down (queryInterface, Sequelize) {
|
||||
async down (queryInterface, /*Sequelize*/) {
|
||||
return queryInterface.dropTable('Roles');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,19 +2,69 @@ const bcrypt = require("bcryptjs");
|
|||
|
||||
/** @type {import('sequelize-cli').Migration} */
|
||||
module.exports = {
|
||||
async up (queryInterface, Sequelize) {
|
||||
return queryInterface.bulkInsert('Users', [{
|
||||
firstName: 'Nolan',
|
||||
lastName: 'Ryan',
|
||||
dateOfBirth: new Date(1947, 1, 31),
|
||||
email: 'ryan.nolan@bullpen.com',
|
||||
password: bcrypt.hashSync('nolan', 8),
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}]);
|
||||
async up (queryInterface, /*Sequelize*/) {
|
||||
await queryInterface.bulkInsert('Authentications', [
|
||||
{ email: 'player@example.com', password: bcrypt.hashSync('hash1234', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||
{ email: 'coach@example.com', password: bcrypt.hashSync('hash2345', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||
{ email: 'admin@example.com', password: bcrypt.hashSync('hash3456', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||
]);
|
||||
|
||||
const auths = await queryInterface.select(null, 'Authentications');
|
||||
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) {
|
||||
return queryInterface.dropTable('Users');
|
||||
async down (queryInterface, /*Sequelize*/) {
|
||||
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)
|
||||
.post("/api/auth/login")
|
||||
.send({
|
||||
email: 'ryan.nolan@bullpen.com',
|
||||
password: 'nolan'
|
||||
email: 'player@example.com',
|
||||
password: 'hash1234'
|
||||
});
|
||||
const user = response.body;
|
||||
|
||||
|
|
@ -38,6 +38,6 @@ describe("Test bullpen session", () => {
|
|||
.set('x-access-token', user.accessToken);
|
||||
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",
|
||||
dateOfBirth: "1956-11-23",
|
||||
email: "hans.zimmer@email.com",
|
||||
password: "secret123"
|
||||
password: "secret123",
|
||||
roles: ['admin']
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ describe("Test retrieving pitch types", () => {
|
|||
let response = await request(app)
|
||||
.post("/api/auth/login")
|
||||
.send({
|
||||
email: 'ryan.nolan@bullpen.com',
|
||||
password: 'nolan'
|
||||
email: 'player@example.com',
|
||||
password: 'hash1234'
|
||||
});
|
||||
const user = response.body;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ describe("Test user authentication", () => {
|
|||
let response = await request(app)
|
||||
.post("/api/auth/login")
|
||||
.send({
|
||||
email: 'ryan.nolan@bullpen.com',
|
||||
password: 'nolan'
|
||||
email: signupUser.email,
|
||||
password: signupUser.password,
|
||||
});
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.accessToken).not.toBeNull();
|
||||
|
|
|
|||
Loading…
Reference in New Issue