restructured user, auth, role models

This commit is contained in:
Sascha Kühl 2025-04-06 14:03:17 +02:00
parent 26edfd46fe
commit 69427f1809
19 changed files with 377 additions and 268 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.idea/ .idea/
node_modules/ node_modules/
backend/.env

20
backend/.env.template Normal file
View File

@ -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

View File

@ -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;

View File

@ -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,
}, },
}; };

View File

@ -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,
}); });

View File

@ -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({

View File

@ -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');
}
};

View File

@ -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');
} }
}; };

View File

@ -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');
} }
}; };

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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(),
}); });

View File

@ -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;
}; };

View File

@ -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');
} }
}; };

View File

@ -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');
} }
}; };

View File

@ -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));
}); });
}) })

View File

@ -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 = {

View File

@ -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;

View File

@ -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();