From 37e57039f154b65d8d31050d75f8f9dce470c5e9 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Tue, 13 Aug 2024 14:37:18 +0100 Subject: [PATCH 01/12] Added get movies, create movie, get movie by id, update movies functions --- .env.example | 6 ---- src/controllers/movies.js | 60 +++++++++++++++++++++++++++++++++++++++ src/domains/movies.js | 50 ++++++++++++++++++++++++++++++++ src/routers/movies.js | 22 ++++++++++++++ src/server.js | 3 ++ 5 files changed, 135 insertions(+), 6 deletions(-) delete mode 100644 .env.example create mode 100644 src/controllers/movies.js create mode 100644 src/domains/movies.js create mode 100644 src/routers/movies.js diff --git a/.env.example b/.env.example deleted file mode 100644 index 60f3a816..00000000 --- a/.env.example +++ /dev/null @@ -1,6 +0,0 @@ -DATABASE_URL="YOUR_DB_URL" - -# We need the following URL environment variable for test purposes: -# - TEST_DATABASE_URL must be a **completely separate** database from any other used in this file - -TEST_DATABASE_URL="YOUR_TEST_DB_URL" diff --git a/src/controllers/movies.js b/src/controllers/movies.js new file mode 100644 index 00000000..475b5aab --- /dev/null +++ b/src/controllers/movies.js @@ -0,0 +1,60 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const { + getAllMoviesdb, + createdMoviedb, + getMoviedb, + updatedMoviedb +} = require("../domains/movies"); + +const getAllMovies = async(req, res) => { + try { + const allMovies = await getAllMoviesdb(); + + res.status(200).json({ movies: allMovies }); + } catch (err) { + console.log("Error:", err); + } +} + +const createMovie = async(req, res) => { + try { + const {title, runtimeMins} = req.body; + const createdMovie = await createdMoviedb(title, runtimeMins); + + res.status(201).json({ movie: createdMovie }); + } catch (err) { + console.log("Error:", err); + } +} + +const getMovieByID = async(req, res) => { + try { + const id = Number(req.params.id); + const { title, runtimeMins } = req.body; + + const movie = await getMoviedb(id); + res.status(200).json({ movie: movie }); + } catch (err) { + console.log("Error:", err); + } +} + +const updateMovie = async(req, res) => { + try { + const id = Number(req.params.id); + const { title, runtimeMins } = req.body; + + const updatedMovie = await updatedMoviedb(id, title, runtimeMins); + + res.status(201).json({ movie: updatedMovie }); + } catch (err) { + console.log("Error:", err); + } +} + +module.exports = { + getAllMovies, + createMovie, + getMovieByID, + updateMovie +}; \ No newline at end of file diff --git a/src/domains/movies.js b/src/domains/movies.js new file mode 100644 index 00000000..d350f216 --- /dev/null +++ b/src/domains/movies.js @@ -0,0 +1,50 @@ +const prisma = require("../utils/prisma"); + +const getAllMoviesdb = async () => + await prisma.movie.findMany({ + include: { + screenings: true, + }, + }); + +const createdMoviedb = async (title, runtimeMins) => + await prisma.movie.create({ + data: { + title, + runtimeMins, + }, + include: { + screenings: true, + }, + }); + +const getMoviedb = async (id) => + await prisma.movie.findUnique({ + where: { + id, + }, + include: { + screenings: true, + }, + }); + + const updatedMoviedb = async (id, title, runtimeMins) => + await prisma.movie.update({ + data: { + title, + runtimeMins, + }, + where: { + id, + }, + include: { + screenings: true, + }, + }); + +module.exports = { + getAllMoviesdb, + createdMoviedb, + getMoviedb, + updatedMoviedb, +}; diff --git a/src/routers/movies.js b/src/routers/movies.js new file mode 100644 index 00000000..5f244ad8 --- /dev/null +++ b/src/routers/movies.js @@ -0,0 +1,22 @@ +const router = require("express").Router(); +const { + getAllMovies, + createMovie, + getMovieByID, + updateMovie +} = require("../controllers/movies"); + +//Get all movies +router.get("/", getAllMovies); + +//Create a movie +router.post("/", createMovie); + +//Get movie by ID: +router.get("/:id", getMovieByID); + +//Update movie by ID: +router.put("/:id", updateMovie) + + +module.exports = router; \ No newline at end of file diff --git a/src/server.js b/src/server.js index 93d47a16..9154cfb1 100644 --- a/src/server.js +++ b/src/server.js @@ -17,5 +17,8 @@ app.use(express.urlencoded({ extended: true })); const customerRouter = require('./routers/customer'); app.use('/customers', customerRouter); +const moviesRouter = require('./routers/movies'); +app.use('/movies', moviesRouter); + module.exports = app From 08cdddf2aa98218222e4246db3758c942ab4fec8 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Tue, 13 Aug 2024 18:20:33 +0100 Subject: [PATCH 02/12] Added update customer function --- src/controllers/customer.js | 19 +++++++++++++++++-- src/domains/customer.js | 14 +++++++++++++- src/domains/movies.js | 26 +++++++++++++------------- src/routers/customer.js | 5 ++++- src/server.js | 22 ++++++++++------------ 5 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 775cfb42..e30f94cb 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -1,5 +1,5 @@ const { PrismaClientKnownRequestError } = require("@prisma/client") -const { createCustomerDb } = require('../domains/customer.js') +const { createCustomerDb, updatedCustomerdb } = require('../domains/customer.js') const createCustomer = async (req, res) => { const { @@ -43,6 +43,21 @@ const createCustomer = async (req, res) => { } } +const updateCustomer = async (req, res) => { + try { + const id = Number(req.params.id); + const { name } = req.body; + + const updatedCustomer = await updatedCustomerdb(id, name); + + res.status(201).json({ customer: updatedCustomer }); + } catch (err) { + console.log("Error:", err); + } +} + + module.exports = { - createCustomer + createCustomer, + updateCustomer } diff --git a/src/domains/customer.js b/src/domains/customer.js index c7f315fd..84278abf 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -21,6 +21,18 @@ const createCustomerDb = async (name, phone, email) => await prisma.customer.cre } }) +const updatedCustomerdb = async (id, name) => await prisma.customer.update({ + data: { + name + }, + where: { + id, + }, + include: { + contact: true, + }, +}) module.exports = { - createCustomerDb + createCustomerDb, + updatedCustomerdb } diff --git a/src/domains/movies.js b/src/domains/movies.js index d350f216..3bfc3268 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -28,19 +28,19 @@ const getMoviedb = async (id) => }, }); - const updatedMoviedb = async (id, title, runtimeMins) => - await prisma.movie.update({ - data: { - title, - runtimeMins, - }, - where: { - id, - }, - include: { - screenings: true, - }, - }); +const updatedMoviedb = async (id, title, runtimeMins) => + await prisma.movie.update({ + data: { + title, + runtimeMins, + }, + where: { + id, + }, + include: { + screenings: true, + }, + }); module.exports = { getAllMoviesdb, diff --git a/src/routers/customer.js b/src/routers/customer.js index f14a87fc..7851de61 100644 --- a/src/routers/customer.js +++ b/src/routers/customer.js @@ -1,6 +1,6 @@ const express = require("express"); const { - createCustomer + createCustomer, updateCustomer } = require('../controllers/customer'); const router = express.Router(); @@ -10,4 +10,7 @@ const router = express.Router(); // that looks like http://localhost:4040/customer/register router.post("/register", createCustomer); +//Update a customer +router.put("/:id", updateCustomer); + module.exports = router; diff --git a/src/server.js b/src/server.js index 9154cfb1..8199aa28 100644 --- a/src/server.js +++ b/src/server.js @@ -1,24 +1,22 @@ -const express = require('express'); +const express = require("express"); const app = express(); -const cors = require('cors'); -const morgan = require('morgan'); +const cors = require("cors"); +const morgan = require("morgan"); -app.disable('x-powered-by'); +app.disable("x-powered-by"); // Add middleware app.use(cors()); -app.use(morgan('dev')); +app.use(morgan("dev")); app.use(express.json()); app.use(express.urlencoded({ extended: true })); - // Tell express to use your routers here -const customerRouter = require('./routers/customer'); -app.use('/customers', customerRouter); - -const moviesRouter = require('./routers/movies'); -app.use('/movies', moviesRouter); +const customerRouter = require("./routers/customer"); +app.use("/customers", customerRouter); +const moviesRouter = require("./routers/movies"); +app.use("/movies", moviesRouter); -module.exports = app +module.exports = app; From 756f933a01de7034d5e099e3ada486b9b2728ebc Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Tue, 13 Aug 2024 18:29:34 +0100 Subject: [PATCH 03/12] Added create screen function --- src/controllers/screens.js | 17 +++++++++++++++++ src/domains/screens.js | 14 ++++++++++++++ src/routers/screens.js | 9 +++++++++ src/server.js | 3 +++ 4 files changed, 43 insertions(+) create mode 100644 src/controllers/screens.js create mode 100644 src/domains/screens.js create mode 100644 src/routers/screens.js diff --git a/src/controllers/screens.js b/src/controllers/screens.js new file mode 100644 index 00000000..ae9d0bb9 --- /dev/null +++ b/src/controllers/screens.js @@ -0,0 +1,17 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const { createdScreendb } = require("../domains/screens"); + +const createScreen = async (req, res) => { + try { + const { number } = req.body; + const createdScreen = await createdScreendb(number); + + res.status(201).json({ screen: createdScreen }); + } catch (err) { + console.log("Error:", err); + } +}; + +module.exports = { + createScreen, +}; diff --git a/src/domains/screens.js b/src/domains/screens.js new file mode 100644 index 00000000..d9fe6495 --- /dev/null +++ b/src/domains/screens.js @@ -0,0 +1,14 @@ +const prisma = require("../utils/prisma"); + + +const createdScreendb = async (number) => + await prisma.screen.create({ + data: { + number, + } + }); + + + module.exports = { + createdScreendb + }; diff --git a/src/routers/screens.js b/src/routers/screens.js new file mode 100644 index 00000000..5d42f670 --- /dev/null +++ b/src/routers/screens.js @@ -0,0 +1,9 @@ +const router = require("express").Router(); +const { + createScreen +} = require("../controllers/screens"); + +//Create a screen +router.post("/", createScreen); + +module.exports = router; \ No newline at end of file diff --git a/src/server.js b/src/server.js index 8199aa28..214ac7d0 100644 --- a/src/server.js +++ b/src/server.js @@ -19,4 +19,7 @@ app.use("/customers", customerRouter); const moviesRouter = require("./routers/movies"); app.use("/movies", moviesRouter); +const screensRouter = require("./routers/screens"); +app.use("/screens", screensRouter); + module.exports = app; From 401e841850dca641e16307e463f1b02d6919b7f9 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Wed, 14 Aug 2024 12:53:30 +0100 Subject: [PATCH 04/12] Added function to filter movies greater than runtimeGt and less than runtimeLt --- src/controllers/movies.js | 4 +++- src/domains/movies.js | 27 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/controllers/movies.js b/src/controllers/movies.js index 475b5aab..634fad3e 100644 --- a/src/controllers/movies.js +++ b/src/controllers/movies.js @@ -8,7 +8,9 @@ const { const getAllMovies = async(req, res) => { try { - const allMovies = await getAllMoviesdb(); + const runtimeLt = Number(req.query.runtimeLt); + const runtimeGt = Number(req.query.runtimeGt); + const allMovies = await getAllMoviesdb(runtimeLt, runtimeGt); res.status(200).json({ movies: allMovies }); } catch (err) { diff --git a/src/domains/movies.js b/src/domains/movies.js index 3bfc3268..a1d08096 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -1,7 +1,32 @@ const prisma = require("../utils/prisma"); -const getAllMoviesdb = async () => +const getAllMoviesdb = async (runtimeLt, runtimeGt) => await prisma.movie.findMany({ + where: { + // Using 'or' statment which means one or more conditions must return true. In this case either runtimeLt OR runtimeGt must be true/added. + OR: [ + { + //This statement means that if runtimeLt query has been added then return all movies with a runtime less than (lt) runtimeLt. If NO runtimeLt has been searched, do nothing. Adding this enables all movies to still be returned even if no runtimeLt/runtimeGt has been searched. + ...(runtimeLt + ? { + runtimeMins: { + lt: runtimeLt, + }, + } + : {}), + }, + { + //Again conditonal statement added here which will still allow for all movies to be returned even if runtimeGt has not been added. + ...(runtimeGt + ? { + runtimeMins: { + gt: runtimeGt, + }, + } + : {}), + }, + ], + }, include: { screenings: true, }, From 6308f8d448175977dd714d65ab673d80393b8f9b Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Wed, 14 Aug 2024 19:13:05 +0100 Subject: [PATCH 05/12] Added extra function to movies, customers. screens. tickets --- src/controllers/customer.js | 4 +- src/controllers/movies.js | 81 +++++++++++++++++------------- src/controllers/screens.js | 4 +- src/controllers/tickets.js | 17 +++++++ src/domains/customer.js | 36 +++++++++----- src/domains/movies.js | 98 ++++++++++++++++++++++++------------- src/domains/screens.js | 21 ++++++-- src/domains/tickets.js | 28 +++++++++++ src/routers/tickets.js | 7 +++ src/server.js | 2 + 10 files changed, 210 insertions(+), 88 deletions(-) create mode 100644 src/controllers/tickets.js create mode 100644 src/domains/tickets.js create mode 100644 src/routers/tickets.js diff --git a/src/controllers/customer.js b/src/controllers/customer.js index e30f94cb..86289f7e 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -46,9 +46,9 @@ const createCustomer = async (req, res) => { const updateCustomer = async (req, res) => { try { const id = Number(req.params.id); - const { name } = req.body; + const { name, contact } = req.body; - const updatedCustomer = await updatedCustomerdb(id, name); + const updatedCustomer = await updatedCustomerdb(id, name, contact); res.status(201).json({ customer: updatedCustomer }); } catch (err) { diff --git a/src/controllers/movies.js b/src/controllers/movies.js index 634fad3e..3750f5b7 100644 --- a/src/controllers/movies.js +++ b/src/controllers/movies.js @@ -3,60 +3,73 @@ const { getAllMoviesdb, createdMoviedb, getMoviedb, - updatedMoviedb + updatedMoviedb, } = require("../domains/movies"); -const getAllMovies = async(req, res) => { - try { - const runtimeLt = Number(req.query.runtimeLt); - const runtimeGt = Number(req.query.runtimeGt); - const allMovies = await getAllMoviesdb(runtimeLt, runtimeGt); +const getAllMovies = async (req, res) => { + try { + const runtimeLt = Number(req.query.runtimeLt); + const runtimeGt = Number(req.query.runtimeGt); - res.status(200).json({ movies: allMovies }); - } catch (err) { - console.log("Error:", err); - } -} + const allMovies = await getAllMoviesdb(runtimeLt, runtimeGt); -const createMovie = async(req, res) => { - try { - const {title, runtimeMins} = req.body; - const createdMovie = await createdMoviedb(title, runtimeMins); + res.status(200).json({ movies: allMovies }); + } catch (err) { + console.log("Error:", err); + } +}; - res.status(201).json({ movie: createdMovie }); - } catch (err) { - console.log("Error:", err); +const createMovie = async (req, res) => { + const { title, runtimeMins, screenings } = req.body; + + if (!title || !runtimeMins ) { + return res.status(400).json({ + error: "Missing fields in request body", + }); } -} -const getMovieByID = async(req, res) => { - try { - const id = Number(req.params.id); - const { title, runtimeMins } = req.body; + try { + const createdMovie = await createdMoviedb(title, runtimeMins, screenings); - const movie = await getMoviedb(id); - res.status(200).json({ movie: movie }); - } catch (err) { - console.log("Error:", err); - } -} + res.status(201).json({ movie: createdMovie }); + } catch (err) { + console.log("Error:", err); + } +}; -const updateMovie = async(req, res) => { +const getMovieByID = async (req, res) => { try { const id = Number(req.params.id); const { title, runtimeMins } = req.body; - const updatedMovie = await updatedMoviedb(id, title, runtimeMins); + const movie = await getMoviedb(id); + res.status(200).json({ movie: movie }); + } catch (err) { + console.log("Error:", err); + } +}; + +const updateMovie = async (req, res) => { + try { + const id = Number(req.params.id); + const { title, runtimeMins, screenings } = req.body; + + const updatedMovie = await updatedMoviedb( + id, + title, + runtimeMins, + screenings + ); res.status(201).json({ movie: updatedMovie }); } catch (err) { console.log("Error:", err); } -} +}; module.exports = { getAllMovies, createMovie, getMovieByID, - updateMovie -}; \ No newline at end of file + updateMovie, +}; diff --git a/src/controllers/screens.js b/src/controllers/screens.js index ae9d0bb9..ec1762ed 100644 --- a/src/controllers/screens.js +++ b/src/controllers/screens.js @@ -3,8 +3,8 @@ const { createdScreendb } = require("../domains/screens"); const createScreen = async (req, res) => { try { - const { number } = req.body; - const createdScreen = await createdScreendb(number); + const { number, screenings } = req.body; + const createdScreen = await createdScreendb(number, screenings); res.status(201).json({ screen: createdScreen }); } catch (err) { diff --git a/src/controllers/tickets.js b/src/controllers/tickets.js new file mode 100644 index 00000000..ff5a5af8 --- /dev/null +++ b/src/controllers/tickets.js @@ -0,0 +1,17 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const { createdTicketdb } = require("../domains/tickets"); + +const createTicket = async (req, res) => { + try { + const { screeningId, customerId } = req.body; + const createdTicket = await createdTicketdb(screeningId, customerId); + + res.status(201).json({ ticket: createdTicket }); + } catch (err) { + console.log("Error:", err); + } +}; + +module.exports = { + createTicket, +}; \ No newline at end of file diff --git a/src/domains/customer.js b/src/domains/customer.js index 84278abf..aeebd1ae 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -21,17 +21,31 @@ const createCustomerDb = async (name, phone, email) => await prisma.customer.cre } }) -const updatedCustomerdb = async (id, name) => await prisma.customer.update({ - data: { - name - }, - where: { - id, - }, - include: { - contact: true, - }, -}) +const updatedCustomerdb = async (id, name, contact) => { + const customerData = { + name, + }; + + if (contact) { + customerData.contact = { + update: { + data: contact, + }, + }; + } + + return await prisma.customer.update({ + data: customerData, + where: { + id, + }, + include: { + contact: true, + }, + }); +}; + + module.exports = { createCustomerDb, updatedCustomerdb diff --git a/src/domains/movies.js b/src/domains/movies.js index a1d08096..0ebc9902 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -3,45 +3,60 @@ const prisma = require("../utils/prisma"); const getAllMoviesdb = async (runtimeLt, runtimeGt) => await prisma.movie.findMany({ where: { - // Using 'or' statment which means one or more conditions must return true. In this case either runtimeLt OR runtimeGt must be true/added. - OR: [ - { - //This statement means that if runtimeLt query has been added then return all movies with a runtime less than (lt) runtimeLt. If NO runtimeLt has been searched, do nothing. Adding this enables all movies to still be returned even if no runtimeLt/runtimeGt has been searched. - ...(runtimeLt - ? { - runtimeMins: { - lt: runtimeLt, - }, - } - : {}), - }, - { - //Again conditonal statement added here which will still allow for all movies to be returned even if runtimeGt has not been added. - ...(runtimeGt - ? { - runtimeMins: { - gt: runtimeGt, - }, - } - : {}), - }, - ], + //This means IF runtimeLt/runtimeGt has been added then apply the where clause, otherwise doe nothing. Adding this enables all movies to still be returned even if no runtimeLt/runtimeGt has been searched. + ...(runtimeLt || runtimeGt + ? { + // Using 'or' statment which means one or more conditions must return true. In this case either runtimeLt OR runtimeGt must be true/added. + OR: [ + { + //This statement means that if runtimeLt query has been added then return all movies with a runtime less than (lt) runtimeLt. If NO runtimeLt has been searched, do nothing. This means code will not break if no runtimeLt is added. Gives the user options. + ...(runtimeLt + ? { + runtimeMins: { + lt: runtimeLt, + }, + } + : {}), + }, + { + ...(runtimeGt + ? { + runtimeMins: { + gt: runtimeGt, + }, + } + : {}), + }, + ], + } + : {}), }, include: { screenings: true, }, }); -const createdMoviedb = async (title, runtimeMins) => - await prisma.movie.create({ - data: { - title, - runtimeMins, - }, +const createdMoviedb = async (title, runtimeMins, screenings) => { + const movieData = { + title, + runtimeMins, + }; + + if (screenings) { + movieData.screenings = { + createMany: { + data: screenings, + }, + }; + } + + return await prisma.movie.create({ + data: movieData, include: { screenings: true, }, }); +}; const getMoviedb = async (id) => await prisma.movie.findUnique({ @@ -53,12 +68,24 @@ const getMoviedb = async (id) => }, }); -const updatedMoviedb = async (id, title, runtimeMins) => - await prisma.movie.update({ - data: { - title, - runtimeMins, - }, +const updatedMoviedb = async (id, title, runtimeMins, screenings) => { + const movieData = { + title, + runtimeMins, + }; + + if (screenings) { + movieData.screenings = { + deleteMany: {}, + createMany: { + data: screenings, + } + }; + + console.log("data", screenings); + } + return await prisma.movie.update({ + data: movieData, where: { id, }, @@ -66,6 +93,7 @@ const updatedMoviedb = async (id, title, runtimeMins) => screenings: true, }, }); +}; module.exports = { getAllMoviesdb, diff --git a/src/domains/screens.js b/src/domains/screens.js index d9fe6495..d8e73ac1 100644 --- a/src/domains/screens.js +++ b/src/domains/screens.js @@ -1,12 +1,25 @@ const prisma = require("../utils/prisma"); +const createdScreendb = async (number, screenings) => { + const screenData = { + number, + }; + + if (screenings) { + screenData.screenings = { + createMany: { + data: screenings, + }, + }; + } -const createdScreendb = async (number) => - await prisma.screen.create({ - data: { - number, + return await prisma.screen.create({ + data: screenData, + include: { + screenings: true } }); +}; module.exports = { diff --git a/src/domains/tickets.js b/src/domains/tickets.js new file mode 100644 index 00000000..5712a707 --- /dev/null +++ b/src/domains/tickets.js @@ -0,0 +1,28 @@ +const prisma = require("../utils/prisma"); + +const createdTicketdb = async (screeningId, customerId) => + await prisma.ticket.create({ + data: { + screeningId, + customerId, + }, + include: { + screening: true, + screening: { + include: { + movie: true, + screen: true, + }, + }, + customer: true, + customer: { + include: { + contact: true, + }, + }, + }, + }); + +module.exports = { + createdTicketdb, +}; diff --git a/src/routers/tickets.js b/src/routers/tickets.js new file mode 100644 index 00000000..8fbce938 --- /dev/null +++ b/src/routers/tickets.js @@ -0,0 +1,7 @@ +const router = require("express").Router(); +const { createTicket } = require("../controllers/tickets"); + +//Create a ticket +router.post("/", createTicket); + +module.exports = router; diff --git a/src/server.js b/src/server.js index 214ac7d0..e684dfa6 100644 --- a/src/server.js +++ b/src/server.js @@ -22,4 +22,6 @@ app.use("/movies", moviesRouter); const screensRouter = require("./routers/screens"); app.use("/screens", screensRouter); +const ticketsRouter = require("./routers/tickets"); app.use("/tickets", ticketsRouter) + module.exports = app; From abb8c90da6caf6abddb96f16bba9c3f81d957588 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Thu, 15 Aug 2024 14:37:01 +0100 Subject: [PATCH 06/12] Started errors --- .../20240814183117_model/migration.sql | 12 ++++ prisma/schema.prisma | 4 +- src/controllers/movies.js | 64 ++++++++++++++----- src/domains/movies.js | 7 +- 4 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 prisma/migrations/20240814183117_model/migration.sql diff --git a/prisma/migrations/20240814183117_model/migration.sql b/prisma/migrations/20240814183117_model/migration.sql new file mode 100644 index 00000000..f8077248 --- /dev/null +++ b/prisma/migrations/20240814183117_model/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - A unique constraint covering the columns `[title]` on the table `Movie` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[number]` on the table `Screen` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "Movie_title_key" ON "Movie"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "Screen_number_key" ON "Screen"("number"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index dd9b27f1..12612b4c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -33,7 +33,7 @@ model Contact { model Movie { id Int @id @default(autoincrement()) screenings Screening[] - title String + title String @unique runtimeMins Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -41,7 +41,7 @@ model Movie { model Screen { id Int @id @default(autoincrement()) - number Int + number Int @unique screenings Screening[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt diff --git a/src/controllers/movies.js b/src/controllers/movies.js index 3750f5b7..3606dc1f 100644 --- a/src/controllers/movies.js +++ b/src/controllers/movies.js @@ -20,40 +20,59 @@ const getAllMovies = async (req, res) => { }; const createMovie = async (req, res) => { - const { title, runtimeMins, screenings } = req.body; - - if (!title || !runtimeMins ) { - return res.status(400).json({ - error: "Missing fields in request body", - }); - } + const { title, runtimeMins, screenings } = req.body; + + if (!title || !runtimeMins) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } try { const createdMovie = await createdMoviedb(title, runtimeMins, screenings); res.status(201).json({ movie: createdMovie }); } catch (err) { - console.log("Error:", err); + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2002") { + return res.status(409).json({ + error: "A movie with the provided title already exists", + }); + } + } + res.status(500).json({ error: err.message }); } }; const getMovieByID = async (req, res) => { try { const id = Number(req.params.id); - const { title, runtimeMins } = req.body; - + const movie = await getMoviedb(id); res.status(200).json({ movie: movie }); } catch (err) { - console.log("Error:", err); + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2025") { + return res.status(405).json({ + error: "A movie with that id does not exist", + }); + } + } + res.status(500).json({ error: err.message }); } }; const updateMovie = async (req, res) => { - try { - const id = Number(req.params.id); - const { title, runtimeMins, screenings } = req.body; + const id = Number(req.params.id); + const { title, runtimeMins, screenings } = req.body; + if (!title || !runtimeMins) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + + try { const updatedMovie = await updatedMoviedb( id, title, @@ -63,7 +82,22 @@ const updateMovie = async (req, res) => { res.status(201).json({ movie: updatedMovie }); } catch (err) { - console.log("Error:", err); + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2025") { + return res.status(405).json({ + error: "A movie with that id does not exist", + }); + } + } + + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2002") { + return res.status(409).json({ + error: "A movie with the provided title already exists", + }); + } + } + res.status(500).json({ error: err.message }); } }; diff --git a/src/domains/movies.js b/src/domains/movies.js index 0ebc9902..e5b812cb 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -58,15 +58,16 @@ const createdMoviedb = async (title, runtimeMins, screenings) => { }); }; -const getMoviedb = async (id) => - await prisma.movie.findUnique({ +const getMoviedb = async (id) => { + return await prisma.movie.findUniqueOrThrow({ where: { - id, + id, }, include: { screenings: true, }, }); +}; const updatedMoviedb = async (id, title, runtimeMins, screenings) => { const movieData = { From 6a78a3691ddffa82ca61601b12cb9ae7d8d81590 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Thu, 15 Aug 2024 15:39:25 +0100 Subject: [PATCH 07/12] Added all errors --- src/controllers/customer.js | 52 +++++++++++++++++++++++-------------- src/controllers/movies.js | 4 +-- src/controllers/screens.js | 18 +++++++++++-- src/controllers/tickets.js | 20 +++++++++++--- 4 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 86289f7e..16392687 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -1,17 +1,16 @@ -const { PrismaClientKnownRequestError } = require("@prisma/client") -const { createCustomerDb, updatedCustomerdb } = require('../domains/customer.js') +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const { + createCustomerDb, + updatedCustomerdb, +} = require("../domains/customer.js"); const createCustomer = async (req, res) => { - const { - name, - phone, - email - } = req.body + const { name, phone, email } = req.body; if (!name || !phone || !email) { return res.status(400).json({ - error: "Missing fields in request body" - }) + error: "Missing fields in request body", + }); } // Try-catch is a very common way to handle errors in JavaScript. @@ -22,9 +21,9 @@ const createCustomer = async (req, res) => { // instead of the Prisma error being thrown (and the app potentially crashing) we exit the // `try` block (bypassing the `res.status` code) and enter the `catch` block. try { - const createdCustomer = await createCustomerDb(name, phone, email) + const createdCustomer = await createCustomerDb(name, phone, email); - res.status(201).json({ customer: createdCustomer }) + res.status(201).json({ customer: createdCustomer }); } catch (e) { // In this catch block, we are able to specify how different Prisma errors are handled. // Prisma throws errors with its own codes. P2002 is the error code for @@ -35,29 +34,44 @@ const createCustomer = async (req, res) => { // HTTP error codes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses if (e instanceof PrismaClientKnownRequestError) { if (e.code === "P2002") { - return res.status(409).json({ error: "A customer with the provided email already exists" }) + return res + .status(409) + .json({ error: "A customer with the provided email already exists" }); } } - res.status(500).json({ error: e.message }) + res.status(500).json({ error: e.message }); } -} +}; const updateCustomer = async (req, res) => { try { const id = Number(req.params.id); const { name, contact } = req.body; + if (!name) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + const updatedCustomer = await updatedCustomerdb(id, name, contact); res.status(201).json({ customer: updatedCustomer }); } catch (err) { - console.log("Error:", err); + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2025") { + return res.status(404).json({ + error: "A customer with that id does not exist", + }); + } + } + //This error message will run if something goes wrong with the errors. + res.status(500).json({ error: err.message }); } -} - +}; module.exports = { createCustomer, - updateCustomer -} + updateCustomer, +}; diff --git a/src/controllers/movies.js b/src/controllers/movies.js index 3606dc1f..49367e69 100644 --- a/src/controllers/movies.js +++ b/src/controllers/movies.js @@ -53,7 +53,7 @@ const getMovieByID = async (req, res) => { } catch (err) { if (err instanceof PrismaClientKnownRequestError) { if (err.code === "P2025") { - return res.status(405).json({ + return res.status(404).json({ error: "A movie with that id does not exist", }); } @@ -84,7 +84,7 @@ const updateMovie = async (req, res) => { } catch (err) { if (err instanceof PrismaClientKnownRequestError) { if (err.code === "P2025") { - return res.status(405).json({ + return res.status(404).json({ error: "A movie with that id does not exist", }); } diff --git a/src/controllers/screens.js b/src/controllers/screens.js index ec1762ed..816e7649 100644 --- a/src/controllers/screens.js +++ b/src/controllers/screens.js @@ -2,13 +2,27 @@ const { PrismaClientKnownRequestError } = require("@prisma/client"); const { createdScreendb } = require("../domains/screens"); const createScreen = async (req, res) => { + const { number, screenings } = req.body; + + if (!number) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + try { - const { number, screenings } = req.body; const createdScreen = await createdScreendb(number, screenings); res.status(201).json({ screen: createdScreen }); } catch (err) { - console.log("Error:", err); + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2002") { + return res.status(409).json({ + error: "A screen with the provided number already exists", + }); + } + } + res.status(500).json({ error: err.message }); } }; diff --git a/src/controllers/tickets.js b/src/controllers/tickets.js index ff5a5af8..78929ec9 100644 --- a/src/controllers/tickets.js +++ b/src/controllers/tickets.js @@ -2,16 +2,30 @@ const { PrismaClientKnownRequestError } = require("@prisma/client"); const { createdTicketdb } = require("../domains/tickets"); const createTicket = async (req, res) => { + const { screeningId, customerId } = req.body; + if (!screeningId || !customerId) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + try { - const { screeningId, customerId } = req.body; const createdTicket = await createdTicketdb(screeningId, customerId); res.status(201).json({ ticket: createdTicket }); } catch (err) { - console.log("Error:", err); + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2003") { + return res.status(404).json({ + error: "A customer or screening does not exist with the provided id", + }); + } + } + res.status(500).json({ error: err.message }); + } }; module.exports = { createTicket, -}; \ No newline at end of file +}; From 0cb048594d848afb2c8fd793cbc15da2d43b1d63 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Fri, 16 Aug 2024 16:55:05 +0100 Subject: [PATCH 08/12] Added tests for extension functions --- src/controllers/movies.js | 2 +- src/domains/movies.js | 67 +++++------- test/api/extensions/movies-ext.spec.js | 139 ++++++++++++++++++++++++ test/api/extensions/screens-ext.spec.js | 28 +++++ test/api/extensions/tickets-ext.spec.js | 36 ++++++ 5 files changed, 234 insertions(+), 38 deletions(-) create mode 100644 test/api/extensions/movies-ext.spec.js create mode 100644 test/api/extensions/screens-ext.spec.js create mode 100644 test/api/extensions/tickets-ext.spec.js diff --git a/src/controllers/movies.js b/src/controllers/movies.js index 49367e69..a758abc8 100644 --- a/src/controllers/movies.js +++ b/src/controllers/movies.js @@ -46,7 +46,7 @@ const createMovie = async (req, res) => { const getMovieByID = async (req, res) => { try { - const id = Number(req.params.id); + const id = req.params.id; const movie = await getMoviedb(id); res.status(200).json({ movie: movie }); diff --git a/src/domains/movies.js b/src/domains/movies.js index e5b812cb..82b94f91 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -1,40 +1,21 @@ const prisma = require("../utils/prisma"); -const getAllMoviesdb = async (runtimeLt, runtimeGt) => - await prisma.movie.findMany({ +const getAllMoviesdb = async (runtimeLt, runtimeGt) => { + + const runTimeClauses = { + ...(runtimeLt && { lt: (runtimeLt) }), + ...(runtimeGt && { gt: (runtimeGt) }), + }; + + return await prisma.movie.findMany({ where: { - //This means IF runtimeLt/runtimeGt has been added then apply the where clause, otherwise doe nothing. Adding this enables all movies to still be returned even if no runtimeLt/runtimeGt has been searched. - ...(runtimeLt || runtimeGt - ? { - // Using 'or' statment which means one or more conditions must return true. In this case either runtimeLt OR runtimeGt must be true/added. - OR: [ - { - //This statement means that if runtimeLt query has been added then return all movies with a runtime less than (lt) runtimeLt. If NO runtimeLt has been searched, do nothing. This means code will not break if no runtimeLt is added. Gives the user options. - ...(runtimeLt - ? { - runtimeMins: { - lt: runtimeLt, - }, - } - : {}), - }, - { - ...(runtimeGt - ? { - runtimeMins: { - gt: runtimeGt, - }, - } - : {}), - }, - ], - } - : {}), + runtimeMins: runTimeClauses, }, include: { screenings: true, }, }); +}; const createdMoviedb = async (title, runtimeMins, screenings) => { const movieData = { @@ -59,14 +40,26 @@ const createdMoviedb = async (title, runtimeMins, screenings) => { }; const getMoviedb = async (id) => { - return await prisma.movie.findUniqueOrThrow({ - where: { - id, - }, - include: { - screenings: true, - }, - }); + //NaN means if not a number. !Nan means if a number. + if (!isNaN(id)) { + return await prisma.movie.findUniqueOrThrow({ + where: { + id: Number(id), + }, + include: { + screenings: true, + }, + }); + } else { + return await prisma.movie.findUniqueOrThrow({ + where: { + title: id, + }, + include: { + screenings: true, + }, + }); + } }; const updatedMoviedb = async (id, title, runtimeMins, screenings) => { diff --git a/test/api/extensions/movies-ext.spec.js b/test/api/extensions/movies-ext.spec.js new file mode 100644 index 00000000..8aa9c245 --- /dev/null +++ b/test/api/extensions/movies-ext.spec.js @@ -0,0 +1,139 @@ +const supertest = require("supertest"); +const app = require("../../../src/server.js"); +const { createMovie } = require("../../helpers/createMovie.js"); +const { createScreen } = require("../../helpers/createScreen.js"); + +describe("Movies Endpoint", () => { + describe("GET /movies?runtimeLt", () => { + it("will retrieve a list of movies with runtime less than runtimeLt", async () => { + await createMovie("Movie 1", 130); + await createMovie("Movie 2", 113); + await createMovie("Movie 3", 84); + + const response = await supertest(app).get("/movies?runtimeLt=115"); + + expect(response.status).toEqual(200); + expect(response.body.movies).not.toEqual(undefined); + expect(response.body.movies.length).toEqual(2); + + const [movie2, movie3] = response.body.movies; + expect(movie2.title).toEqual("Movie 2"); + expect(movie2.runtimeMins).toEqual(113); + + expect(movie3.title).toEqual("Movie 3"); + expect(movie3.runtimeMins).toEqual(84); + }); + }); + + describe("GET /movies?runtimeGt", () => { + it("will retrieve a list of movies with runtime more than runtimeGt", async () => { + await createMovie("Movie 1", 130); + await createMovie("Movie 2", 113); + await createMovie("Movie 3", 84); + + const response = await supertest(app).get("/movies?runtimeGt=90"); + + expect(response.status).toEqual(200); + expect(response.body.movies).not.toEqual(undefined); + expect(response.body.movies.length).toEqual(2); + + const [movie1, movie2] = response.body.movies; + expect(movie1.title).toEqual("Movie 1"); + expect(movie1.runtimeMins).toEqual(130); + + expect(movie2.title).toEqual("Movie 2"); + expect(movie2.runtimeMins).toEqual(113); + }); + }); + + describe("GET /movies?runtimeLt&runtimeGt", () => { + it("will retrieve a list of movies with a runtime between runtimeLt and runtimeGt", async () => { + await createMovie("Movie 1", 130); + await createMovie("Movie 2", 113); + await createMovie("Movie 3", 84); + + const response = await supertest(app).get( + "/movies?runtimeLt=160&runtimeGt=90" + ); + + expect(response.status).toEqual(200); + expect(response.body.movies).not.toEqual(undefined); + expect(response.body.movies.length).toEqual(2); + + const [movie1, movie2] = response.body.movies; + expect(movie1.title).toEqual("Movie 1"); + expect(movie1.runtimeMins).toEqual(130); + + expect(movie2.title).toEqual("Movie 2"); + expect(movie2.runtimeMins).toEqual(113); + }); + }); + + describe("POST /movies", () => { + it("will add screenings if screenings exist in the body", async () => { + const screen1 = await createScreen(1); + const screen2 = await createScreen(2); + + const request = { + title: "Top Gun", + runtimeMins: 110, + screenings: [ + { screenId: screen1.id, startsAt: "2024-08-11T15:30:00.000Z" }, + { screenId: screen2.id, startsAt: "2024-08-17T18:30:00.000Z" }, + ], + }; + + const response = await supertest(app).post("/movies").send(request); + + expect(response.status).toEqual(201); + expect(response.body.movie).not.toEqual(undefined); + expect(response.body.movie.title).toEqual("Top Gun"); + expect(response.body.movie.runtimeMins).toEqual(110); + expect(response.body.movie.screenings).not.toEqual(undefined); + expect(response.body.movie.screenings.length).toEqual(2); + }); + }); + + describe("GET /movies/title", () => { + it("will get movies by title", async () => { + const screen = await createScreen(1); + const movie = await createMovie("Dodgeball", 120, screen); + + const response = await supertest(app).get(`/movies/${movie.title}`); + + expect(response.status).toEqual(200); + expect(response.body.movie).not.toEqual(undefined); + expect(response.body.movie.title).toEqual("Dodgeball"); + expect(response.body.movie.runtimeMins).toEqual(120); + expect(response.body.movie.screenings).not.toEqual(undefined); + }); + + describe("PUT /movies/:id", () => { + it("will update a movie by id and screening if provided", async () => { + const screen1 = await createScreen(1); + const screen2 = await createScreen(2); + const movie = await createMovie("Dodgeball", 120, screen1); + + const request = { + title: "Scream", + runtimeMins: 113, + screenings: [ + { screenId: screen1.id, startsAt: "2024-08-11T15:30:00.000Z" }, + { screenId: screen2.id, startsAt: "2024-08-17T18:30:00.000Z" }, + ], + }; + + const response = await supertest(app) + .put(`/movies/${movie.id}`) + .send(request); + + expect(response.status).toEqual(201); + expect(response.body.movie).not.toEqual(undefined); + expect(response.body.movie.title).toEqual("Scream"); + expect(response.body.movie.runtimeMins).toEqual(113); + expect(response.body.movie.screenings).not.toEqual(undefined); + expect(response.body.movie.screenings.length).toEqual(2); + }); + }); + }); +}); diff --git a/test/api/extensions/screens-ext.spec.js b/test/api/extensions/screens-ext.spec.js new file mode 100644 index 00000000..5d00667b --- /dev/null +++ b/test/api/extensions/screens-ext.spec.js @@ -0,0 +1,28 @@ +const supertest = require("supertest"); +const app = require("../../../src/server.js"); +const { createMovie } = require("../../helpers/createMovie.js"); + +describe("Screens Endpoint", () => { + describe("POST /screens", () => { + it("will create a screen and screening if provided", async () => { + const movie1 = await createMovie("Movie 1", 130); + const movie2 = await createMovie("Movie 2", 113); + + const request = { + number: 15, + screenings: [ + { movieId: movie1.id, startsAt: "2024-08-11T15:30:00.000Z" }, + { movieId: movie2.id, startsAt: "2024-08-17T18:30:00.000Z" }, + ], + }; + + const response = await supertest(app).post("/screens").send(request); + + expect(response.status).toEqual(201); + expect(response.body.screen).not.toEqual(undefined); + expect(response.body.screen.number).toEqual(15); + expect(response.body.screen.screenings).not.toEqual(undefined); + expect(response.body.screen.screenings.length).toEqual(2); + }); + }); +}); diff --git a/test/api/extensions/tickets-ext.spec.js b/test/api/extensions/tickets-ext.spec.js new file mode 100644 index 00000000..10ac266f --- /dev/null +++ b/test/api/extensions/tickets-ext.spec.js @@ -0,0 +1,36 @@ +const supertest = require("supertest"); +const app = require("../../../src/server.js"); +const { createMovie } = require("../../helpers/createMovie.js"); +const { createScreen } = require("../../helpers/createScreen.js"); +const { createCustomer } = require("../../helpers/createCustomer.js"); + +describe("Tickets Endpoint", () => { + describe("POST /tickets", () => { + it("will create a ticket and include the data for the customer, contact details, movie, screening and screen", async () => { + const screen = await createScreen(1); + const customer = await createCustomer("John", "123456", "john@test.com"); + const movie = await createMovie("Movie 1", 130, screen); + + const request = { + screeningId: movie.screenings[0].id, + customerId: customer.id, + }; + + const response = await supertest(app).post("/tickets").send(request); + + expect(response.status).toEqual(201); + expect(response.body.ticket).not.toEqual(undefined); + expect(response.body.ticket.screening).not.toEqual(undefined); + expect(response.body.ticket.screening.screen.number).toEqual(1); + expect(response.body.ticket.screening.movie.title).toEqual("Movie 1"); + expect(response.body.ticket.screening.movie.runtimeMins).toEqual(130); + expect(response.body.ticket.screening.screen.number).toEqual(1); + expect(response.body.ticket.customer).not.toEqual(undefined); + expect(response.body.ticket.customer.name).toEqual("John"); + expect(response.body.ticket.customer.contact.phone).toEqual("123456"); + expect(response.body.ticket.customer.contact.email).toEqual( + "john@test.com" + ); + }); + }); +}); From 9be2b9ab9b5103aa0d40c8cb358fb667fd282468 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Fri, 16 Aug 2024 18:47:37 +0100 Subject: [PATCH 09/12] Added tests for extension errors --- src/controllers/movies.js | 23 ++-- src/domains/movies.js | 3 +- test/api/extensions/movies-ext.spec.js | 155 +++++++++++++++++------- test/api/extensions/screens-ext.spec.js | 22 ++++ test/api/extensions/tickets-ext.spec.js | 21 ++++ 5 files changed, 172 insertions(+), 52 deletions(-) diff --git a/src/controllers/movies.js b/src/controllers/movies.js index a758abc8..3c533c42 100644 --- a/src/controllers/movies.js +++ b/src/controllers/movies.js @@ -1,4 +1,7 @@ const { PrismaClientKnownRequestError } = require("@prisma/client"); +const prisma = require("../utils/prisma"); + + const { getAllMoviesdb, createdMoviedb, @@ -72,6 +75,18 @@ const updateMovie = async (req, res) => { }); } + const existingTitle = await prisma.movie.findUnique({ + where: { + title: title, + }, + }); + + if(existingTitle) { + return res.status(409).json({ + error: "Title already exists", + }); + } + try { const updatedMovie = await updatedMoviedb( id, @@ -89,14 +104,6 @@ const updateMovie = async (req, res) => { }); } } - - if (err instanceof PrismaClientKnownRequestError) { - if (err.code === "P2002") { - return res.status(409).json({ - error: "A movie with the provided title already exists", - }); - } - } res.status(500).json({ error: err.message }); } }; diff --git a/src/domains/movies.js b/src/domains/movies.js index 82b94f91..9c6f8434 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -75,9 +75,8 @@ const updatedMoviedb = async (id, title, runtimeMins, screenings) => { data: screenings, } }; - - console.log("data", screenings); } + return await prisma.movie.update({ data: movieData, where: { diff --git a/test/api/extensions/movies-ext.spec.js b/test/api/extensions/movies-ext.spec.js index 8aa9c245..029c7f0c 100644 --- a/test/api/extensions/movies-ext.spec.js +++ b/test/api/extensions/movies-ext.spec.js @@ -92,48 +92,119 @@ describe("Movies Endpoint", () => { expect(response.body.movie.screenings).not.toEqual(undefined); expect(response.body.movie.screenings.length).toEqual(2); }); + + it("will return 400 when there are missing fields in the request body", async () => { + const request = {}; + + const response = await supertest(app).post(`/movies`).send(request); + + expect(response.status).toEqual(400); + expect(response.body).toHaveProperty("error"); + }); + + it("will return 409 when a movie with hte provided title already exists", async () => { + const movie1 = await createMovie("Movie 1", 130); + + const request = { + title: "Movie 1", + runtimeMins: 130, + }; + + const response = await supertest(app).post(`/movies`).send(request); + + expect(response.status).toEqual(409); + expect(response.body).toHaveProperty("error"); + }); }); - describe("GET /movies/title", () => { - it("will get movies by title", async () => { - const screen = await createScreen(1); - const movie = await createMovie("Dodgeball", 120, screen); - - const response = await supertest(app).get(`/movies/${movie.title}`); - - expect(response.status).toEqual(200); - expect(response.body.movie).not.toEqual(undefined); - expect(response.body.movie.title).toEqual("Dodgeball"); - expect(response.body.movie.runtimeMins).toEqual(120); - expect(response.body.movie.screenings).not.toEqual(undefined); - }); - - describe("PUT /movies/:id", () => { - it("will update a movie by id and screening if provided", async () => { - const screen1 = await createScreen(1); - const screen2 = await createScreen(2); - const movie = await createMovie("Dodgeball", 120, screen1); - - const request = { - title: "Scream", - runtimeMins: 113, - screenings: [ - { screenId: screen1.id, startsAt: "2024-08-11T15:30:00.000Z" }, - { screenId: screen2.id, startsAt: "2024-08-17T18:30:00.000Z" }, - ], - }; - - const response = await supertest(app) - .put(`/movies/${movie.id}`) - .send(request); - - expect(response.status).toEqual(201); - expect(response.body.movie).not.toEqual(undefined); - expect(response.body.movie.title).toEqual("Scream"); - expect(response.body.movie.runtimeMins).toEqual(113); - expect(response.body.movie.screenings).not.toEqual(undefined); - expect(response.body.movie.screenings.length).toEqual(2); - }); - }); - }); + describe("GET /movies/title", () => { + it("will get movies by title", async () => { + const screen = await createScreen(1); + const movie = await createMovie("Dodgeball", 120, screen); + + const response = await supertest(app).get(`/movies/${movie.title}`); + + expect(response.status).toEqual(200); + expect(response.body.movie).not.toEqual(undefined); + expect(response.body.movie.title).toEqual("Dodgeball"); + expect(response.body.movie.runtimeMins).toEqual(120); + expect(response.body.movie.screenings).not.toEqual(undefined); + }); + + it("will return 404 if the movie or title is not found", async () => { + const response = await supertest(app).get(`/movies/10000`); + + expect(response.status).toEqual(404); + expect(response.body).toHaveProperty("error"); + }); + }); + + describe("PUT /movies/:id", () => { + it("will update a movie by id and screening if provided", async () => { + const screen1 = await createScreen(1); + const screen2 = await createScreen(2); + const movie = await createMovie("Dodgeball", 120, screen1); + + const request = { + title: "Scream", + runtimeMins: 113, + screenings: [ + { screenId: screen1.id, startsAt: "2024-08-11T15:30:00.000Z" }, + { screenId: screen2.id, startsAt: "2024-08-17T18:30:00.000Z" }, + ], + }; + + const response = await supertest(app) + .put(`/movies/${movie.id}`) + .send(request); + + expect(response.status).toEqual(201); + expect(response.body.movie).not.toEqual(undefined); + expect(response.body.movie.title).toEqual("Scream"); + expect(response.body.movie.runtimeMins).toEqual(113); + expect(response.body.movie.screenings).not.toEqual(undefined); + expect(response.body.movie.screenings.length).toEqual(2); + }); + + it("will return 404 if the movie with that id is not found", async () => { + const request = { + title: "Updated name", + runtimeMins: 120, + }; + + const response = await supertest(app).put(`/movies/10000`).send(request); + + expect(response.status).toEqual(404); + expect(response.body).toHaveProperty("error"); + }); + + it("will return 400 when there are missing fields in the request body", async () => { + const movie = await createMovie("Dodgeball", 120); + const request = {}; + + const response = await supertest(app) + .put(`/movies/${movie.id}`) + .send(request); + + expect(response.status).toEqual(400); + expect(response.body).toHaveProperty("error"); + }); + + it("will return 409 when a movie with the provided title already exists", async () => { + const screen1 = await createScreen(1); + const movie1 = await createMovie("Movie 1", 130, screen1); + + const request = { + title: movie1.title, + runtimeMins: movie1.runtimeMins, + }; + + const response = await supertest(app) + .put(`/movies/${movie1.id}`) + .send(request); + + expect(response.status).toEqual(409); + expect(response.body).toHaveProperty("error"); + }); + }); }); diff --git a/test/api/extensions/screens-ext.spec.js b/test/api/extensions/screens-ext.spec.js index 5d00667b..c0011505 100644 --- a/test/api/extensions/screens-ext.spec.js +++ b/test/api/extensions/screens-ext.spec.js @@ -1,6 +1,7 @@ const supertest = require("supertest"); const app = require("../../../src/server.js"); const { createMovie } = require("../../helpers/createMovie.js"); +const { createScreen } = require("../../helpers/createScreen.js"); describe("Screens Endpoint", () => { describe("POST /screens", () => { @@ -24,5 +25,26 @@ describe("Screens Endpoint", () => { expect(response.body.screen.screenings).not.toEqual(undefined); expect(response.body.screen.screenings.length).toEqual(2); }); + + it("will return 400 when there are missing fields in the request body", async () => { + const request = {}; + + const response = await supertest(app).post(`/screens`).send(request); + + expect(response.status).toEqual(400); + expect(response.body).toHaveProperty("error"); + }); + + it("will return 409 when a screen with the provided number already exists", async () => { + const screen1 = await createScreen(1); + const request = { + number: screen1.number, + }; + + const response = await supertest(app).post(`/screens`).send(request); + + expect(response.status).toEqual(409); + expect(response.body).toHaveProperty("error"); + }); }); }); diff --git a/test/api/extensions/tickets-ext.spec.js b/test/api/extensions/tickets-ext.spec.js index 10ac266f..fdc8c4c2 100644 --- a/test/api/extensions/tickets-ext.spec.js +++ b/test/api/extensions/tickets-ext.spec.js @@ -32,5 +32,26 @@ describe("Tickets Endpoint", () => { "john@test.com" ); }); + + it("will return 404 if the movie with that id is not found", async () => { + const request = { + screeningId: 1000, + customerId: 1001 + }; + + const response = await supertest(app).post(`/tickets`).send(request); + + expect(response.status).toEqual(404); + expect(response.body).toHaveProperty("error"); + }); + + it("will return 400 when there are missing fields in the request body", async () => { + const request = {}; + + const response = await supertest(app).post(`/tickets`).send(request); + + expect(response.status).toEqual(400); + expect(response.body).toHaveProperty("error"); + }); }); }); From 14563dfbca22dfaded27dc838f7f7a9edb100877 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Fri, 16 Aug 2024 19:02:11 +0100 Subject: [PATCH 10/12] Added function to get movies with future screening times --- src/domains/movies.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/domains/movies.js b/src/domains/movies.js index 9c6f8434..e11fddbf 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -6,7 +6,9 @@ const getAllMoviesdb = async (runtimeLt, runtimeGt) => { ...(runtimeLt && { lt: (runtimeLt) }), ...(runtimeGt && { gt: (runtimeGt) }), }; - + const currentDate = new Date(); + + if (runtimeGt || runtimeLt) { return await prisma.movie.findMany({ where: { runtimeMins: runTimeClauses, @@ -15,7 +17,23 @@ const getAllMoviesdb = async (runtimeLt, runtimeGt) => { screenings: true, }, }); -}; +} else { + return await prisma.movie.findMany({ + where: { + screenings: { + some: { + startsAt: { + gt: currentDate + } + } + } + }, + include: { + screenings: true, + }, +}) +} +} const createdMoviedb = async (title, runtimeMins, screenings) => { const movieData = { From 05e8a597d5aa424795e5dc6a284a47bb9db7b695 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Fri, 16 Aug 2024 19:06:11 +0100 Subject: [PATCH 11/12] Tweaked code --- src/domains/movies.js | 65 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/domains/movies.js b/src/domains/movies.js index e11fddbf..61d9690b 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -1,39 +1,38 @@ const prisma = require("../utils/prisma"); const getAllMoviesdb = async (runtimeLt, runtimeGt) => { - const runTimeClauses = { - ...(runtimeLt && { lt: (runtimeLt) }), - ...(runtimeGt && { gt: (runtimeGt) }), + ...(runtimeLt && { lt: runtimeLt }), + ...(runtimeGt && { gt: runtimeGt }), }; - const currentDate = new Date(); - + const currentDate = new Date(); + if (runtimeGt || runtimeLt) { - return await prisma.movie.findMany({ - where: { - runtimeMins: runTimeClauses, - }, - include: { - screenings: true, - }, - }); -} else { - return await prisma.movie.findMany({ - where: { - screenings: { - some: { - startsAt: { - gt: currentDate - } - } - } - }, - include: { - screenings: true, - }, -}) -} -} + return await prisma.movie.findMany({ + where: { + runtimeMins: runTimeClauses, + }, + include: { + screenings: true, + }, + }); + } else { + return await prisma.movie.findMany({ + // where: { + // screenings: { + // some: { + // startsAt: { + // gt: currentDate + // } + // } + // } + // }, + include: { + screenings: true, + }, + }); + } +}; const createdMoviedb = async (title, runtimeMins, screenings) => { const movieData = { @@ -89,12 +88,12 @@ const updatedMoviedb = async (id, title, runtimeMins, screenings) => { if (screenings) { movieData.screenings = { deleteMany: {}, - createMany: { + createMany: { data: screenings, - } + }, }; } - + return await prisma.movie.update({ data: movieData, where: { From 5f5b9358e279ec4ba49cdf3db870885f5339b5e2 Mon Sep 17 00:00:00 2001 From: Zainab Choudhry Date: Mon, 19 Aug 2024 17:13:20 +0100 Subject: [PATCH 12/12] Tweaked code again --- src/domains/movies.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/domains/movies.js b/src/domains/movies.js index 61d9690b..85a1871a 100644 --- a/src/domains/movies.js +++ b/src/domains/movies.js @@ -2,9 +2,20 @@ const prisma = require("../utils/prisma"); const getAllMoviesdb = async (runtimeLt, runtimeGt) => { const runTimeClauses = { - ...(runtimeLt && { lt: runtimeLt }), - ...(runtimeGt && { gt: runtimeGt }), + ...(runtimeLt + ? { + lt: runtimeLt, + } + : {}), + + ...(runtimeGt + ? { + gt: runtimeGt, + } + : {}), }; + + console.log("run time clauses", runTimeClauses); const currentDate = new Date(); if (runtimeGt || runtimeLt) {