Compare commits

..

No commits in common. "751953ae70207e018456f4d3851c34eb03a896c4" and "677f929f1cd283c628cee0e0fefc85b1943983d7" have entirely different histories.

17 changed files with 94 additions and 222 deletions

View File

@ -18,7 +18,7 @@ app.use(express.urlencoded({ extended: true }));
const db = require("./models");
const Role = db.Role;
const User = db.User;
const PitchType = db.PitchType;
const PitchType = db.pitchType;
db.sequelize.sync();
// force: true will drop the table if it already exists
@ -36,12 +36,12 @@ app.get("/", (req, res) => {
require('./routes/auth.routes')(app);
require('./routes/user.routes')(app);
require('./routes/pitchType.routes')(app);
require('./routes/bullpenSession.routes')(app);
function initial() {
Role.bulkCreate([
{ name: 'user' },
{ name: 'administrator' },
{ name: 'moderator' },
{ name: 'administrato' },
]);
User.bulkCreate([
{ firstName: 'Nolan', lastName: 'Ryan', dateOfBirth: new Date(1947, 1, 31), email: 'ryan.nolan@bullpen.com', password: bcrypt.hashSync('nolan', 8) },

View File

@ -6,7 +6,7 @@ const Op = db.Sequelize.Op;
const jwt = require("jsonwebtoken");
exports.register = (req, res) => {
exports.signup = (req, res) => {
// Save User to Database
User.create({
firstName: req.body.firstName,
@ -42,7 +42,7 @@ exports.register = (req, res) => {
});
};
exports.login = (req, res) => {
exports.signin = (req, res) => {
User.findOne({
where: {
email: req.body.email
@ -92,10 +92,6 @@ exports.login = (req, res) => {
});
};
exports.logout = (req, res) => {
}
exports.refreshToken = async (req, res) => {
const { refreshToken: requestToken } = req.body;
@ -117,7 +113,7 @@ exports.refreshToken = async (req, res) => {
RefreshToken.destroy({ where: { id: refreshToken.id } });
res.status(403).json({
message: "Refresh token was expired. Please make a new login request",
message: "Refresh token was expired. Please make a new signin request",
});
return;
}

View File

@ -1,53 +0,0 @@
const db = require("../models/index");
const BullpenSession = db.BullpenSession;
const Pitch = db.Pitch;
exports.insert = (req, res) => {
BullpenSession.create(req.body, { include: [{
model: Pitch,
as: 'pitches'
}]}
)
.then(bullpenSession => {
return res.status(201).send(bullpenSession);
})
.catch(err => {
res.status(500).send({ message: err.message });
});
};
exports.findAll = (req, res) => {
BullpenSession.findAll({
include: {
model: Pitch,
as: 'pitches'
}
})
.then(bullpenSessions => {
res.status(200).send(bullpenSessions);
});
}
exports.findOne = (req, res) => {
const id = req.params.id;
BullpenSession.findByPk(id, {
include: {
model: Pitch,
as: 'pitches'
}
})
.then(data => {
if (data) {
res.send(data);
} else {
res.status(404).send({
message: `Cannot find bullpen session with id=${id}.`
});
}
})
.catch(err => {
res.status(500).send({
message: `Error retrieving bullpen session with id=${id}: ${err.message}`
});
});
}

View File

@ -1,5 +1,6 @@
const db = require("../models/index");
const PitchType = db.PitchType;
const PitchType = db.pitchType;
const Op = db.Sequelize.Op;
exports.findAll = (req, res) => {
PitchType.findAll()
@ -29,7 +30,7 @@ exports.findOne = (req, res) => {
})
.catch(err => {
res.status(500).send({
message: `Error retrieving pitch type with id=${id}: ${err.message}`
message: "Error retrieving pitch type with id=" + id
});
});
};

View File

@ -27,9 +27,6 @@ module.exports = {
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
pitchTime: {
type: Sequelize.DATE,
},
aimedArea: {
type: Sequelize.INTEGER
},

View File

@ -1,5 +1,7 @@
'use strict';
const { Model } = require('sequelize');
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class BullpenSession extends Model {
/**
@ -13,11 +15,19 @@ module.exports = (sequelize, DataTypes) => {
as: 'pitches',
});
BullpenSession.belongsTo(models.User, {
foreignKey: "pitcherId"
as: "pitcher"
});
}
}
BullpenSession.init({
pitcherId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'User',
key: 'id'
}
},
startedAt: {
type: DataTypes.DATE,
allowNull: false,
@ -32,4 +42,4 @@ module.exports = (sequelize, DataTypes) => {
tableName: 'BullpenSessions'
});
return BullpenSession;
};
};

View File

@ -1,4 +1,7 @@
const { Model } = require('sequelize');
'use strict';
const {
Model, DataTypes
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Pitch extends Model {
/**
@ -9,16 +12,27 @@ module.exports = (sequelize, DataTypes) => {
static associate(models) {
Pitch.belongsTo(models.BullpenSession, {
foreignKey: 'bullpenSessionId',
as: 'bullpenSession'
});
Pitch.belongsTo(models.PitchType, {
foreignKey: 'pitchTypeId'
});
Pitch.belongsTo(models.PitchType);
}
}
Pitch.init({
pitchTime: {
type: DataTypes.DATE,
allowNull: false
pitchTypeId: {
type: DataTypes.INTEGER,
allowNull: false,
references: { // User belongsTo PitchType 1:1
model: 'PitchTypes',
key: 'id'
}
},
bullpenSessionId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'BullpenSessions',
key: 'id'
}
},
aimedArea: {
type: DataTypes.INTEGER,
@ -34,4 +48,4 @@ module.exports = (sequelize, DataTypes) => {
tableName: 'Pitches'
});
return Pitch;
};
};

View File

@ -11,15 +11,14 @@ module.exports = function(app) {
});
app.post(
"/api/auth/register",
"/api/auth/signup",
[
verifySignUp.checkDuplicateUsernameOrEmail,
verifySignUp.checkRolesExisted
],
controller.register
controller.signup
);
app.post("/api/auth/login", controller.login);
app.post("/api/auth/logout", controller.logout);
app.post("/api/auth/signin", controller.signin);
app.post("/api/auth/refreshtoken", controller.refreshToken);
};

View File

@ -1,25 +0,0 @@
const { authJwt } = require("../middleware");
const controller = require("../controllers/bullpenSession.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"x-access-token, Origin, Content-Type, Accept"
);
next();
});
app.post(
"/api/bullpen_session",
[authJwt.verifyToken],
controller.insert);
app.get(
"/api/bullpen_session",
[authJwt.verifyToken],
controller.findAll);
app.get(
"/api/bullpen_session/:id",
[authJwt.verifyToken],
controller.findOne);
};

View File

@ -10,12 +10,6 @@ module.exports = function(app) {
next();
});
app.get(
"/api/pitch_types",
[authJwt.verifyToken],
controller.findAll);
app.get(
"/api/pitch_types/:id",
[authJwt.verifyToken],
controller.findOne);
app.get("/api/pitch_types", controller.findAll);
app.get("/api/pitch_types/:id", controller.findOne);
};

View File

@ -17,6 +17,11 @@ module.exports = {
},
async down (queryInterface, Sequelize) {
return queryInterface.dropTable('Roles');
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
}
};

View File

@ -15,6 +15,11 @@ module.exports = {
},
async down (queryInterface, Sequelize) {
return queryInterface.dropTable('Users');
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
}
};

View File

@ -1,18 +1,25 @@
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
return queryInterface.bulkInsert('PitchTypes',[
{ name: 'Fastball', abbreviation: 'FB', createdAt: new Date(), updatedAt: new Date() },
{ name: 'Curveball', abbreviation: 'CB', createdAt: new Date(), updatedAt: new Date() },
{ name: 'Slider', abbreviation: 'SL', createdAt: new Date(), updatedAt: new Date() },
{ name: 'Changeup', abbreviation: 'CH', createdAt: new Date(), updatedAt: new Date() },
{ name: 'Cutter', abbreviation: 'CUT', createdAt: new Date(), updatedAt: new Date() },
{ name: 'Sweeper', abbreviation: 'SW', createdAt: new Date(), updatedAt: new Date() },
{ name: 'Slurve', abbreviation: 'SLV', createdAt: new Date(), updatedAt: new Date() },
]);
/**
* Add seed commands here.
*
* Example:
* await queryInterface.bulkInsert('People', [{
* name: 'John Doe',
* isBetaMember: false
* }], {});
*/
},
async down (queryInterface, Sequelize) {
return queryInterface.dropTable('PitchTypes');
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
}
};

View File

@ -1,43 +0,0 @@
const request = require("supertest")
const {
expect,
describe,
test,
} = require('@jest/globals');
const app = require("../app")
const { bullpenSession } = require("./data/bullpenSession.test.data")
describe("Test bullpen session", () => {
test("should create bullpen session with pitches", async () => {
let response = await request(app)
.post("/api/auth/login")
.send({
email: 'ryan.nolan@bullpen.com',
password: 'nolan'
});
const user = response.body;
response = await request(app)
.post("/api/bullpen_session")
.set('x-access-token', user.accessToken)
.send(bullpenSession);
expect(response.statusCode).toBe(201);
const bullpenSessionData = await response.body;
expect(bullpenSessionData).toBeDefined();
expect(bullpenSessionData.id).toBeDefined();
expect(bullpenSessionData.id).toBeGreaterThan(0);
expect(bullpenSessionData.pitches).toBeDefined();
expect(Array.isArray(bullpenSessionData.pitches)).toBe(true);
expect(bullpenSessionData.pitches.length).toBe(2);
response = await request(app)
.get(`/api/bullpen_session/${bullpenSessionData.id}`)
.set('x-access-token', user.accessToken);
expect(response.statusCode).toBe(200);
console.log(JSON.stringify(response.body, null, 2));
});
})

View File

@ -1,20 +0,0 @@
const bullpenSession = {
pitcherId: 1,
startedAt: new Date(2025, 3, 22, 16, 5, 13),
finishedAt: new Date(2025, 3, 22, 16, 23, 45),
pitches: [{
pitchTypeId: 1,
pitchTime: new Date(2025, 3, 22, 16, 7, 21),
aimedArea: 11,
hitArea: 12
}, {
pitchTypeId: 4,
pitchTime: new Date(2025, 3, 22, 16, 9, 57),
aimedArea: 6,
hitArea: 14
}]
};
module.exports = {
bullpenSession
}

View File

@ -1,26 +0,0 @@
const request = require("supertest")
const {
expect,
describe,
test,
} = require('@jest/globals');
const app = require("../app")
describe("Test retrieving pitch types", () => {
test("should retrieve all pitch types", async () => {
let response = await request(app)
.post("/api/auth/login")
.send({
email: 'ryan.nolan@bullpen.com',
password: 'nolan'
});
const user = response.body;
response = await request(app)
.get('/api/pitch_types')
.set('x-access-token', user.accessToken);
expect(response.statusCode).toBe(200);
expect(response.body.length).toEqual(7);
});
});

View File

@ -3,34 +3,45 @@ const {
expect,
describe,
test,
beforeAll,
afterAll,
} = require('@jest/globals');
const app = require("../app")
const { signupUser } = require("./data/user.test.data")
const res = require("express/lib/response");
describe("Test user authentication", () => {
test("should register a user", async () => {
test("should signup a user", async () => {
const response = await request(app)
.post("/api/auth/register")
.post("/api/auth/signup")
.send(signupUser);
expect(response.header['content-type']).toBe('application/json; charset=utf-8');
expect(response.statusCode).toBe(200);
});
test("Test user login", async() => {
test("Test user login", async () => {
let user = {};
let response = await request(app)
.post("/api/auth/login")
.post("/api/auth/signin")
.send({
email: 'ryan.nolan@bullpen.com',
password: 'nolan'
});
expect(response.statusCode).toBe(200);
expect(response.body.accessToken).not.toBeNull();
const user = response.body;
user = response.body;
response = await request(app)
.get(`/api/users/${user.id}`);
expect(response.statusCode).toBe(403);
response = await request(app)
.get(`/api/users/${user.id}`)
.set('x-access-token', user.accessToken);
console.log(response.body);
expect(response.statusCode).toBe(200);
});
});