From 351199bcc53fa88270f9e1b1eec0893f401e1f95 Mon Sep 17 00:00:00 2001 From: Frida Anselin Date: Tue, 28 Jan 2025 11:33:59 +0100 Subject: [PATCH 1/5] Core complete --- build.gradle | 14 +++- .../java/com/booleanuk/api/cinema/Main.java | 11 ++++ .../api/cinema/customers/Customer.java | 42 ++++++++++++ .../cinema/customers/CustomerController.java | 59 +++++++++++++++++ .../cinema/customers/CustomerRepository.java | 7 ++ .../booleanuk/api/cinema/movies/Movie.java | 51 +++++++++++++++ .../api/cinema/movies/MovieController.java | 64 +++++++++++++++++++ .../api/cinema/movies/MovieRepository.java | 7 ++ .../api/cinema/screenings/Screening.java | 48 ++++++++++++++ .../screenings/ScreeningController.java | 54 ++++++++++++++++ .../screenings/ScreeningRepository.java | 10 +++ 11 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/booleanuk/api/cinema/Main.java create mode 100644 src/main/java/com/booleanuk/api/cinema/customers/Customer.java create mode 100644 src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/customers/CustomerRepository.java create mode 100644 src/main/java/com/booleanuk/api/cinema/movies/Movie.java create mode 100644 src/main/java/com/booleanuk/api/cinema/movies/MovieController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/movies/MovieRepository.java create mode 100644 src/main/java/com/booleanuk/api/cinema/screenings/Screening.java create mode 100644 src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/screenings/ScreeningRepository.java diff --git a/build.gradle b/build.gradle index 3d7f7607..836c7ade 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.3.1' - id 'io.spring.dependency-management' version '1.1.5' + id 'org.springframework.boot' version '3.4.1' + id 'io.spring.dependency-management' version '1.1.7' } group = 'com.booleanuk' @@ -13,6 +13,12 @@ java { } } +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + repositories { mavenCentral() } @@ -20,10 +26,14 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.3' } tasks.named('test') { diff --git a/src/main/java/com/booleanuk/api/cinema/Main.java b/src/main/java/com/booleanuk/api/cinema/Main.java new file mode 100644 index 00000000..c4fb60ea --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/Main.java @@ -0,0 +1,11 @@ +package com.booleanuk.api.cinema; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} diff --git a/src/main/java/com/booleanuk/api/cinema/customers/Customer.java b/src/main/java/com/booleanuk/api/cinema/customers/Customer.java new file mode 100644 index 00000000..5556eacd --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/customers/Customer.java @@ -0,0 +1,42 @@ +package com.booleanuk.api.cinema.customers; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "customers") +public class Customer { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + @Column + private String name; + @Column + private String email; + @Column + private String phone; + @Column + private LocalDateTime createdAt; + @Column + private LocalDateTime updatedAt; + + public Customer(String name, String email, String phone) { + this.name = name; + this.email = email; + this.phone = phone; + } + + public Customer(int id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java new file mode 100644 index 00000000..17ca597b --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java @@ -0,0 +1,59 @@ +package com.booleanuk.api.cinema.customers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("customers") +public class CustomerController { + @Autowired + private CustomerRepository customerRepository; + + @GetMapping + public ResponseEntity> getAllCustomers() { + return ResponseEntity.ok(this.customerRepository.findAll()); + } + + @PostMapping + public ResponseEntity createCustomer(@RequestBody Customer customer) { + customer.setCreatedAt(LocalDateTime.now()); + customer.setUpdatedAt(LocalDateTime.now()); + return new ResponseEntity(this.customerRepository.save(customer), HttpStatus.CREATED); + } + + @GetMapping("{id}") + public ResponseEntity getCustomerById(@PathVariable int id) { + Customer customer = this.customerRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that id found") + ); + return ResponseEntity.ok(customer); + } + + @PutMapping("{id}") + public ResponseEntity updateCustomer(@PathVariable int id, @RequestBody Customer customer) { + Customer customerToUpdate = this.customerRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that id was found") + ); + customerToUpdate.setName(customer.getName()); + customerToUpdate.setEmail(customer.getEmail()); + customerToUpdate.setPhone(customer.getPhone()); + customerToUpdate.setUpdatedAt(LocalDateTime.now()); + return new ResponseEntity(this.customerRepository.save(customerToUpdate), HttpStatus.CREATED); + } + + @DeleteMapping("{id}") + public ResponseEntity deleteCustomerById(@PathVariable int id) { + Customer customerToDelete = this.customerRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that id was found") + ); + this.customerRepository.delete(customerToDelete); + return ResponseEntity.ok(customerToDelete); + } + +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/customers/CustomerRepository.java b/src/main/java/com/booleanuk/api/cinema/customers/CustomerRepository.java new file mode 100644 index 00000000..f7782206 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/customers/CustomerRepository.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.cinema.customers; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CustomerRepository extends JpaRepository { + +} diff --git a/src/main/java/com/booleanuk/api/cinema/movies/Movie.java b/src/main/java/com/booleanuk/api/cinema/movies/Movie.java new file mode 100644 index 00000000..94c61270 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/movies/Movie.java @@ -0,0 +1,51 @@ +package com.booleanuk.api.cinema.movies; + +import com.booleanuk.api.cinema.screenings.Screening; +import com.fasterxml.jackson.annotation.JsonIncludeProperties; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "movies") +public class Movie { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + @Column + private String title; + @Column + private String rating; + @Column + private String description; + @Column + private int runtimeMins; + @Column + private LocalDateTime createdAt; + @Column + private LocalDateTime updatedAt; + + @OneToMany(mappedBy = "movie", cascade = CascadeType.REMOVE) + @JsonIncludeProperties({"screenNumber", "startsAt", "capacity"}) + private List screenings; + + public Movie(String title, String rating, String description, int runtimeMins) { + this.title = title; + this.rating = rating; + this.description = description; + this.runtimeMins = runtimeMins; + } + + public Movie(int id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java b/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java new file mode 100644 index 00000000..63cdbf9d --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java @@ -0,0 +1,64 @@ +package com.booleanuk.api.cinema.movies; + +import com.booleanuk.api.cinema.screenings.Screening; +import com.booleanuk.api.cinema.screenings.ScreeningRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("movies") +public class MovieController { + @Autowired + private MovieRepository movieRepository; + + @GetMapping + public ResponseEntity> getAllMovies() { + return ResponseEntity.ok(this.movieRepository.findAll()); + } + + @PostMapping + public ResponseEntity createMovie(@RequestBody Movie movie) { + movie.setCreatedAt(LocalDateTime.now()); + movie.setUpdatedAt(LocalDateTime.now()); + return new ResponseEntity(this.movieRepository.save(movie), HttpStatus.CREATED); + } + + @GetMapping("{id}") + public ResponseEntity getMovieById(@PathVariable int id) { + Movie movie = this.movieRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id found") + ); + return ResponseEntity.ok(movie); + } + + @PutMapping("{id}") + public ResponseEntity updateMovie(@PathVariable int id, @RequestBody Movie movie) { + Movie movieToUpdate = this.movieRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id was found") + ); + movieToUpdate.setTitle(movie.getTitle()); + movieToUpdate.setRating(movie.getRating()); + movieToUpdate.setDescription(movie.getDescription()); + movieToUpdate.setRuntimeMins(movie.getRuntimeMins()); + movieToUpdate.setUpdatedAt(LocalDateTime.now()); + return new ResponseEntity(this.movieRepository.save(movieToUpdate), HttpStatus.CREATED); + } + + @DeleteMapping("{id}") + public ResponseEntity deleteMovieById(@PathVariable int id) { + Movie movieToDelete = this.movieRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id was found") + ); + this.movieRepository.delete(movieToDelete); + return ResponseEntity.ok(movieToDelete); + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/movies/MovieRepository.java b/src/main/java/com/booleanuk/api/cinema/movies/MovieRepository.java new file mode 100644 index 00000000..db5c44bc --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/movies/MovieRepository.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.cinema.movies; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MovieRepository extends JpaRepository { + +} diff --git a/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java b/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java new file mode 100644 index 00000000..c0fb9695 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java @@ -0,0 +1,48 @@ +package com.booleanuk.api.cinema.screenings; + +import com.booleanuk.api.cinema.movies.Movie; +import com.fasterxml.jackson.annotation.JsonIncludeProperties; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "screenings") +public class Screening { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + @Column + private int screenNumber; + @Column + private LocalDateTime startsAt; + @Column + private int capacity; + @Column + private LocalDateTime createdAt; + @Column + private LocalDateTime updatedAt; + + @ManyToOne + @JoinColumn(name = "movie_id", nullable = false) + @JsonIncludeProperties({"title", "rating", "description", "runtime_mins"}) + private Movie movie; + + public Screening(int screenNumber, LocalDateTime startsAt, int capacity) { + this.screenNumber = screenNumber; + this.startsAt = startsAt; + this.capacity = capacity; + } + + public Screening(int id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java b/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java new file mode 100644 index 00000000..89a9e8fd --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java @@ -0,0 +1,54 @@ +package com.booleanuk.api.cinema.screenings; + +import com.booleanuk.api.cinema.movies.Movie; +import com.booleanuk.api.cinema.movies.MovieRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("movies/{id}/screenings") +public class ScreeningController { + @Autowired + private ScreeningRepository screeningRepository; + + @Autowired + private MovieRepository movieRepository; + + @GetMapping + public ResponseEntity> getAllScreenings(@PathVariable int id) { + Movie movie = this.movieRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id found") + ); + + List screenings = this.screeningRepository.findByMovie(movie); + return ResponseEntity.ok(screenings); + } + + @PostMapping + public ResponseEntity createNewScreening(@PathVariable int id, @RequestBody Screening screening) { + Movie movie = this.movieRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id was found") + ); + + screening.setCreatedAt(LocalDateTime.now()); + screening.setUpdatedAt(LocalDateTime.now()); + screening.setMovie(movie); + return new ResponseEntity<>(this.screeningRepository.save(screening), HttpStatus.CREATED); + } + + @DeleteMapping("{screening_id}") + public ResponseEntity deleteScreening(@PathVariable int id) { + Screening screeningToDelete = this.screeningRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that id was found") + ); + this.screeningRepository.delete(screeningToDelete); + return ResponseEntity.ok(screeningToDelete); + } + +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningRepository.java b/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningRepository.java new file mode 100644 index 00000000..399cfe09 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningRepository.java @@ -0,0 +1,10 @@ +package com.booleanuk.api.cinema.screenings; + +import com.booleanuk.api.cinema.movies.Movie; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface ScreeningRepository extends JpaRepository { + List findByMovie(Movie movie); +} From 5dc565009d6142220ee2a938f8f3e3f16947308d Mon Sep 17 00:00:00 2001 From: Frida Anselin Date: Tue, 28 Jan 2025 14:46:31 +0100 Subject: [PATCH 2/5] Added ticket with 200, 201, 404 HttpStatus codes, missing 400 --- .../api/cinema/customers/Customer.java | 7 ++ .../cinema/customers/CustomerController.java | 10 +++ .../api/cinema/screenings/Screening.java | 6 ++ .../booleanuk/api/cinema/tickets/Ticket.java | 48 +++++++++++++ .../api/cinema/tickets/TicketController.java | 68 +++++++++++++++++++ .../api/cinema/tickets/TicketRepository.java | 11 +++ 6 files changed, 150 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java create mode 100644 src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/tickets/TicketRepository.java diff --git a/src/main/java/com/booleanuk/api/cinema/customers/Customer.java b/src/main/java/com/booleanuk/api/cinema/customers/Customer.java index 5556eacd..9e03c6c4 100644 --- a/src/main/java/com/booleanuk/api/cinema/customers/Customer.java +++ b/src/main/java/com/booleanuk/api/cinema/customers/Customer.java @@ -1,5 +1,7 @@ package com.booleanuk.api.cinema.customers; +import com.booleanuk.api.cinema.tickets.Ticket; +import com.fasterxml.jackson.annotation.JsonIncludeProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; @@ -7,6 +9,7 @@ import lombok.Setter; import java.time.LocalDateTime; +import java.util.List; @Getter @@ -30,6 +33,10 @@ public class Customer { @Column private LocalDateTime updatedAt; + @OneToMany(mappedBy = "customer", cascade = CascadeType.REMOVE) + @JsonIncludeProperties({"customer_id", "screening_id", "num_seats"}) + private List tickets; + public Customer(String name, String email, String phone) { this.name = name; this.email = email; diff --git a/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java index 17ca597b..ff72b0aa 100644 --- a/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java @@ -1,5 +1,6 @@ package com.booleanuk.api.cinema.customers; +import org.apache.coyote.BadRequestException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -22,6 +23,15 @@ public ResponseEntity> getAllCustomers() { @PostMapping public ResponseEntity createCustomer(@RequestBody Customer customer) { + /*try { + customer.setCreatedAt(LocalDateTime.now()); + customer.setUpdatedAt(LocalDateTime.now()); + Customer customerToCreate = this.customerRepository.save(customer); + return new ResponseEntity<>(customerToCreate, HttpStatus.CREATED); + } catch (Exception e) { + throw new BadRequestException("Could not create a new customer, please check all fields are correct"); + //return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + }*/ customer.setCreatedAt(LocalDateTime.now()); customer.setUpdatedAt(LocalDateTime.now()); return new ResponseEntity(this.customerRepository.save(customer), HttpStatus.CREATED); diff --git a/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java b/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java index c0fb9695..aa09525c 100644 --- a/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java @@ -1,6 +1,7 @@ package com.booleanuk.api.cinema.screenings; import com.booleanuk.api.cinema.movies.Movie; +import com.booleanuk.api.cinema.tickets.Ticket; import com.fasterxml.jackson.annotation.JsonIncludeProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -9,6 +10,7 @@ import lombok.Setter; import java.time.LocalDateTime; +import java.util.List; @Getter @Setter @@ -36,6 +38,10 @@ public class Screening { @JsonIncludeProperties({"title", "rating", "description", "runtime_mins"}) private Movie movie; + @OneToMany(mappedBy = "screening", cascade = CascadeType.REMOVE) + @JsonIncludeProperties({"customer_id", "screening_id", "num_seats"}) + private List tickets; + public Screening(int screenNumber, LocalDateTime startsAt, int capacity) { this.screenNumber = screenNumber; this.startsAt = startsAt; diff --git a/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java b/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java new file mode 100644 index 00000000..d2316e0c --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java @@ -0,0 +1,48 @@ +package com.booleanuk.api.cinema.tickets; + +import com.booleanuk.api.cinema.customers.Customer; +import com.booleanuk.api.cinema.screenings.Screening; +import com.fasterxml.jackson.annotation.JsonIncludeProperties; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tickets") +public class Ticket { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + @Column + private int numSeats; + @Column + private LocalDateTime createdAt; + @Column + private LocalDateTime updatedAt; + + @ManyToOne + @JoinColumn(name = "customer_id", nullable = false) + @JsonIncludeProperties({"id", "name", "phone"}) + private Customer customer; + + @ManyToOne + @JoinColumn(name = "screening_id") + @JsonIncludeProperties({"screen_number", "starts_at"}) + private Screening screening; + + public Ticket(int numSeats) { + this.numSeats = numSeats; + } + + public Ticket(int id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java b/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java new file mode 100644 index 00000000..ab5f28bc --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java @@ -0,0 +1,68 @@ +package com.booleanuk.api.cinema.tickets; + +import com.booleanuk.api.cinema.customers.Customer; +import com.booleanuk.api.cinema.customers.CustomerRepository; +import com.booleanuk.api.cinema.screenings.Screening; +import com.booleanuk.api.cinema.screenings.ScreeningRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("customers/{customerId}/screenings/{screeningId}") +public class TicketController { + @Autowired + private TicketRepository ticketRepository; + + @Autowired + private ScreeningRepository screeningRepository; + + @Autowired + private CustomerRepository customerRepository; + + @GetMapping + public ResponseEntity> getAllTickets(@PathVariable int customerId, @PathVariable int screeningId) { + Customer customer = this.customerRepository.findById(customerId).orElse(null); + + Screening screening = this.screeningRepository.findById(screeningId).orElse(null); + + if (customer == null || screening == null) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No ticket found for the customer and screening with those ids"); + } + + List tickets = this.ticketRepository.findByCustomerAndScreening(customer, screening); //findALL? + return ResponseEntity.ok(tickets); + } + + @PostMapping + public ResponseEntity createNewTicket(@PathVariable int customerId, @PathVariable int screeningId, @RequestBody Ticket ticket) { + Customer customer = this.customerRepository.findById(customerId).orElse(null); + + Screening screening = this.screeningRepository.findById(screeningId).orElse(null); + + if (customer == null || screening == null) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer or screening with those ids found"); + } + + ticket.setCreatedAt(LocalDateTime.now()); + ticket.setUpdatedAt(LocalDateTime.now()); + ticket.setCustomer(customer); + ticket.setScreening(screening); + return new ResponseEntity<>(this.ticketRepository.save(ticket), HttpStatus.CREATED); + } + + @DeleteMapping("{ticket_id}") + public ResponseEntity deleteTicket(@PathVariable int id) { + Ticket ticketToDelete = this.ticketRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No ticket with that id was found") + ); + this.ticketRepository.delete(ticketToDelete); + return ResponseEntity.ok(ticketToDelete); + } + +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/tickets/TicketRepository.java b/src/main/java/com/booleanuk/api/cinema/tickets/TicketRepository.java new file mode 100644 index 00000000..291a5145 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/tickets/TicketRepository.java @@ -0,0 +1,11 @@ +package com.booleanuk.api.cinema.tickets; + +import com.booleanuk.api.cinema.customers.Customer; +import com.booleanuk.api.cinema.screenings.Screening; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface TicketRepository extends JpaRepository { + List findByCustomerAndScreening(Customer customer, Screening screening); +} From b108af4c32a0968d2c78a365d54bc016f494750f Mon Sep 17 00:00:00 2001 From: Frida Anselin Date: Tue, 28 Jan 2025 14:49:25 +0100 Subject: [PATCH 3/5] Refactor ticket constructor --- src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java b/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java index d2316e0c..9198e2bb 100644 --- a/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java +++ b/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java @@ -38,7 +38,7 @@ public class Ticket { @JsonIncludeProperties({"screen_number", "starts_at"}) private Screening screening; - public Ticket(int numSeats) { + public Ticket(int id, int numSeats) { this.numSeats = numSeats; } From 045ddeb745410d90291ff90d7856c8cd8498972f Mon Sep 17 00:00:00 2001 From: Frida Anselin Date: Wed, 29 Jan 2025 13:16:52 +0100 Subject: [PATCH 4/5] Add response classes --- .../responses/CustomerListResponse.java | 8 ++++++++ .../cinema/responses/CustomerResponse.java | 6 ++++++ .../api/cinema/responses/ErrorResponse.java | 19 +++++++++++++++++++ .../cinema/responses/MovieListResponse.java | 8 ++++++++ .../api/cinema/responses/MovieResponse.java | 6 ++++++ .../api/cinema/responses/Response.java | 14 ++++++++++++++ .../responses/ScreeningListResponse.java | 8 ++++++++ .../cinema/responses/ScreeningResponse.java | 6 ++++++ .../cinema/responses/TicketListResponse.java | 8 ++++++++ .../api/cinema/responses/TicketResponse.java | 6 ++++++ 10 files changed, 89 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/CustomerListResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/CustomerResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/ErrorResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/MovieListResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/MovieResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/Response.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/ScreeningListResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/ScreeningResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/TicketListResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/TicketResponse.java diff --git a/src/main/java/com/booleanuk/api/cinema/responses/CustomerListResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/CustomerListResponse.java new file mode 100644 index 00000000..db6c23f4 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/CustomerListResponse.java @@ -0,0 +1,8 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.customers.Customer; + +import java.util.List; + +public class CustomerListResponse extends Response>{ +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/CustomerResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/CustomerResponse.java new file mode 100644 index 00000000..2319c0e8 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/CustomerResponse.java @@ -0,0 +1,6 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.customers.Customer; + +public class CustomerResponse extends Response{ +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/ErrorResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/ErrorResponse.java new file mode 100644 index 00000000..2ec2abda --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/ErrorResponse.java @@ -0,0 +1,19 @@ +package com.booleanuk.api.cinema.responses; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +@Getter +@NoArgsConstructor +public class ErrorResponse extends Response>{ + + public void set(String message) { + this.status = "error"; + Map reply = new HashMap<>(); + reply.put("message", message); + this.data = reply; + } +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/MovieListResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/MovieListResponse.java new file mode 100644 index 00000000..52118919 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/MovieListResponse.java @@ -0,0 +1,8 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.movies.Movie; + +import java.util.List; + +public class MovieListResponse extends Response> { +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/MovieResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/MovieResponse.java new file mode 100644 index 00000000..0133554a --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/MovieResponse.java @@ -0,0 +1,6 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.movies.Movie; + +public class MovieResponse extends Response { +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/Response.java b/src/main/java/com/booleanuk/api/cinema/responses/Response.java new file mode 100644 index 00000000..7bbb5f3c --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/Response.java @@ -0,0 +1,14 @@ +package com.booleanuk.api.cinema.responses; + +import lombok.Getter; + +@Getter +public class Response { + protected String status; + protected T data; + + public void set(T data) { + this.status = "success"; + this.data = data; + } +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/ScreeningListResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/ScreeningListResponse.java new file mode 100644 index 00000000..33e1b92c --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/ScreeningListResponse.java @@ -0,0 +1,8 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.screenings.Screening; + +import java.util.List; + +public class ScreeningListResponse extends Response> { +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/ScreeningResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/ScreeningResponse.java new file mode 100644 index 00000000..48c6c1c6 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/ScreeningResponse.java @@ -0,0 +1,6 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.screenings.Screening; + +public class ScreeningResponse extends Response { +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/TicketListResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/TicketListResponse.java new file mode 100644 index 00000000..a9d90e38 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/TicketListResponse.java @@ -0,0 +1,8 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.tickets.Ticket; + +import java.util.List; + +public class TicketListResponse extends Response> { +} diff --git a/src/main/java/com/booleanuk/api/cinema/responses/TicketResponse.java b/src/main/java/com/booleanuk/api/cinema/responses/TicketResponse.java new file mode 100644 index 00000000..8c2a4e16 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/TicketResponse.java @@ -0,0 +1,6 @@ +package com.booleanuk.api.cinema.responses; + +import com.booleanuk.api.cinema.tickets.Ticket; + +public class TicketResponse extends Response { +} From cbd2f72d742898d1a486e0f676008084380f3a00 Mon Sep 17 00:00:00 2001 From: Frida Anselin Date: Wed, 29 Jan 2025 13:17:59 +0100 Subject: [PATCH 5/5] Extension complete --- .../api/cinema/customers/Customer.java | 2 + .../cinema/customers/CustomerController.java | 78 +++++++++++-------- .../api/cinema/movies/MovieController.java | 76 +++++++++++++----- .../api/cinema/screenings/Screening.java | 9 +++ .../screenings/ScreeningController.java | 53 +++++++++---- .../booleanuk/api/cinema/tickets/Ticket.java | 1 + .../api/cinema/tickets/TicketController.java | 39 +++++++--- 7 files changed, 178 insertions(+), 80 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/customers/Customer.java b/src/main/java/com/booleanuk/api/cinema/customers/Customer.java index 9e03c6c4..bbc827ba 100644 --- a/src/main/java/com/booleanuk/api/cinema/customers/Customer.java +++ b/src/main/java/com/booleanuk/api/cinema/customers/Customer.java @@ -1,6 +1,7 @@ package com.booleanuk.api.cinema.customers; import com.booleanuk.api.cinema.tickets.Ticket; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIncludeProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -18,6 +19,7 @@ @AllArgsConstructor @Entity @Table(name = "customers") +@JsonIgnoreProperties({"tickets"}) public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java index ff72b0aa..28acea2c 100644 --- a/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java @@ -1,14 +1,15 @@ package com.booleanuk.api.cinema.customers; -import org.apache.coyote.BadRequestException; +import com.booleanuk.api.cinema.responses.CustomerListResponse; +import com.booleanuk.api.cinema.responses.CustomerResponse; +import com.booleanuk.api.cinema.responses.ErrorResponse; +import com.booleanuk.api.cinema.responses.Response; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; -import java.util.List; @RestController @RequestMapping("customers") @@ -16,54 +17,69 @@ public class CustomerController { @Autowired private CustomerRepository customerRepository; + private ErrorResponse errorResponse = new ErrorResponse(); + private CustomerResponse customerResponse = new CustomerResponse(); + private CustomerListResponse customerListResponse = new CustomerListResponse(); + @GetMapping - public ResponseEntity> getAllCustomers() { - return ResponseEntity.ok(this.customerRepository.findAll()); + public ResponseEntity> getAllCustomers() { + this.customerListResponse.set(this.customerRepository.findAll()); + return ResponseEntity.ok(customerListResponse); } @PostMapping - public ResponseEntity createCustomer(@RequestBody Customer customer) { - /*try { - customer.setCreatedAt(LocalDateTime.now()); - customer.setUpdatedAt(LocalDateTime.now()); - Customer customerToCreate = this.customerRepository.save(customer); - return new ResponseEntity<>(customerToCreate, HttpStatus.CREATED); - } catch (Exception e) { - throw new BadRequestException("Could not create a new customer, please check all fields are correct"); - //return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - }*/ + public ResponseEntity> createCustomer(@RequestBody Customer customer) { customer.setCreatedAt(LocalDateTime.now()); customer.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity(this.customerRepository.save(customer), HttpStatus.CREATED); + if (customer.getName() == null || customer.getEmail() == null || customer.getPhone() == null) { + this.errorResponse.set("Could not create a new customer, please check all fields are correct"); + return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); + } + this.customerResponse.set(this.customerRepository.save(customer)); + return new ResponseEntity<>(customerResponse, HttpStatus.CREATED); } @GetMapping("{id}") - public ResponseEntity getCustomerById(@PathVariable int id) { - Customer customer = this.customerRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that id found") - ); - return ResponseEntity.ok(customer); + public ResponseEntity> getCustomerById(@PathVariable int id) { + Customer customer = this.customerRepository.findById(id).orElse(null); + if (customer == null) { + this.errorResponse.set("No customer with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + this.customerResponse.set(customer); + return ResponseEntity.ok(customerResponse); } @PutMapping("{id}") - public ResponseEntity updateCustomer(@PathVariable int id, @RequestBody Customer customer) { - Customer customerToUpdate = this.customerRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that id was found") - ); + public ResponseEntity> updateCustomer(@PathVariable int id, @RequestBody Customer customer) { + Customer customerToUpdate = this.customerRepository.findById(id).orElse(null); + if (customerToUpdate == null) { + this.errorResponse.set("No customer with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + + if (customer.getName() == null || customer.getEmail() == null || customer.getPhone() == null) { + this.errorResponse.set("Could not update the specified customer, please check all fields are correct"); + return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); + } customerToUpdate.setName(customer.getName()); customerToUpdate.setEmail(customer.getEmail()); customerToUpdate.setPhone(customer.getPhone()); customerToUpdate.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity(this.customerRepository.save(customerToUpdate), HttpStatus.CREATED); + this.customerResponse.set(this.customerRepository.save(customerToUpdate)); + return new ResponseEntity<>(customerResponse, HttpStatus.CREATED); } @DeleteMapping("{id}") - public ResponseEntity deleteCustomerById(@PathVariable int id) { - Customer customerToDelete = this.customerRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that id was found") - ); + public ResponseEntity> deleteCustomerById(@PathVariable int id) { + Customer customerToDelete = this.customerRepository.findById(id).orElse(null); + if (customerToDelete == null) { + this.errorResponse.set("No customer with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } this.customerRepository.delete(customerToDelete); - return ResponseEntity.ok(customerToDelete); + this.customerResponse.set(customerToDelete); + return ResponseEntity.ok(customerResponse); } } \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java b/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java index 63cdbf9d..d12d707c 100644 --- a/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java @@ -1,15 +1,14 @@ package com.booleanuk.api.cinema.movies; +import com.booleanuk.api.cinema.responses.*; import com.booleanuk.api.cinema.screenings.Screening; import com.booleanuk.api.cinema.screenings.ScreeningRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; -import java.util.List; @RestController @RequestMapping("movies") @@ -17,46 +16,81 @@ public class MovieController { @Autowired private MovieRepository movieRepository; + @Autowired + private ScreeningRepository screeningRepository; + + private ErrorResponse errorResponse = new ErrorResponse(); + private MovieResponse movieResponse = new MovieResponse(); + private MovieListResponse movieListResponse = new MovieListResponse(); + private ScreeningResponse screeningResponse = new ScreeningResponse(); + @GetMapping - public ResponseEntity> getAllMovies() { - return ResponseEntity.ok(this.movieRepository.findAll()); + public ResponseEntity> getAllMovies() { + this.movieListResponse.set(this.movieRepository.findAll()); + return ResponseEntity.ok(movieListResponse); } @PostMapping - public ResponseEntity createMovie(@RequestBody Movie movie) { + public ResponseEntity> createMovie(@RequestBody Movie movie) { movie.setCreatedAt(LocalDateTime.now()); movie.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity(this.movieRepository.save(movie), HttpStatus.CREATED); + if (movie.getTitle() == null || movie.getRating() == null || movie.getDescription() == null || movie.getRuntimeMins() <= 0) { + this.errorResponse.set("Could not create a new movie, please check all fields are correct"); + return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); + } + + this.movieResponse.set(this.movieRepository.save(movie)); + if (!(movie.getScreenings() == null)) { + for (Screening screening : movie.getScreenings()) { + screening = new Screening(movie, screening.getScreenNumber(), screening.getStartsAt(), screening.getCapacity()); + this.screeningResponse.set(this.screeningRepository.save(screening)); + } + } + return new ResponseEntity<>(movieResponse, HttpStatus.CREATED); } @GetMapping("{id}") - public ResponseEntity getMovieById(@PathVariable int id) { - Movie movie = this.movieRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id found") - ); - return ResponseEntity.ok(movie); + public ResponseEntity> getMovieById(@PathVariable int id) { + Movie movie = this.movieRepository.findById(id).orElse(null); + if (movie == null) { + this.errorResponse.set("No movie with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + this.movieResponse.set(movie); + return ResponseEntity.ok(movieResponse); } @PutMapping("{id}") - public ResponseEntity updateMovie(@PathVariable int id, @RequestBody Movie movie) { - Movie movieToUpdate = this.movieRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id was found") - ); + public ResponseEntity> updateMovie(@PathVariable int id, @RequestBody Movie movie) { + Movie movieToUpdate = this.movieRepository.findById(id).orElse(null); + if (movieToUpdate == null) { + this.errorResponse.set("No movie with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + + if (movie.getTitle() == null || movie.getRating() == null || movie.getDescription() == null || movie.getRuntimeMins() <= 0) { + this.errorResponse.set("Could not update the specified movie, please check all fields are correct"); + return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); + } movieToUpdate.setTitle(movie.getTitle()); movieToUpdate.setRating(movie.getRating()); movieToUpdate.setDescription(movie.getDescription()); movieToUpdate.setRuntimeMins(movie.getRuntimeMins()); movieToUpdate.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity(this.movieRepository.save(movieToUpdate), HttpStatus.CREATED); + this.movieResponse.set(this.movieRepository.save(movieToUpdate)); + return new ResponseEntity<>(movieResponse, HttpStatus.CREATED); } @DeleteMapping("{id}") - public ResponseEntity deleteMovieById(@PathVariable int id) { - Movie movieToDelete = this.movieRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id was found") - ); + public ResponseEntity> deleteMovieById(@PathVariable int id) { + Movie movieToDelete = this.movieRepository.findById(id).orElse(null); + if (movieToDelete == null) { + this.errorResponse.set("No movie with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } this.movieRepository.delete(movieToDelete); - return ResponseEntity.ok(movieToDelete); + this.movieResponse.set(movieToDelete); + return ResponseEntity.ok(movieResponse); } diff --git a/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java b/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java index aa09525c..f427936e 100644 --- a/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java @@ -2,6 +2,7 @@ import com.booleanuk.api.cinema.movies.Movie; import com.booleanuk.api.cinema.tickets.Ticket; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIncludeProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -18,6 +19,7 @@ @AllArgsConstructor @Entity @Table(name = "screenings") +@JsonIgnoreProperties({"tickets"}) public class Screening { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -42,6 +44,13 @@ public class Screening { @JsonIncludeProperties({"customer_id", "screening_id", "num_seats"}) private List tickets; + public Screening(Movie movie, int screenNumber, LocalDateTime startsAt, int capacity) { + this.movie = movie; + this.screenNumber = screenNumber; + this.startsAt = startsAt; + this.capacity = capacity; + } + public Screening(int screenNumber, LocalDateTime startsAt, int capacity) { this.screenNumber = screenNumber; this.startsAt = startsAt; diff --git a/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java b/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java index 89a9e8fd..8e626202 100644 --- a/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java +++ b/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java @@ -2,11 +2,14 @@ import com.booleanuk.api.cinema.movies.Movie; import com.booleanuk.api.cinema.movies.MovieRepository; +import com.booleanuk.api.cinema.responses.ErrorResponse; +import com.booleanuk.api.cinema.responses.Response; +import com.booleanuk.api.cinema.responses.ScreeningListResponse; +import com.booleanuk.api.cinema.responses.ScreeningResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; import java.util.List; @@ -20,35 +23,53 @@ public class ScreeningController { @Autowired private MovieRepository movieRepository; + private ErrorResponse errorResponse = new ErrorResponse(); + private ScreeningResponse screeningResponse = new ScreeningResponse(); + private ScreeningListResponse screeningListResponse = new ScreeningListResponse(); + @GetMapping - public ResponseEntity> getAllScreenings(@PathVariable int id) { - Movie movie = this.movieRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id found") - ); + public ResponseEntity> getAllScreenings(@PathVariable int id) { + Movie movie = this.movieRepository.findById(id).orElse(null); + if (movie == null) { + this.errorResponse.set("No movie with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } List screenings = this.screeningRepository.findByMovie(movie); - return ResponseEntity.ok(screenings); + this.screeningListResponse.set(screenings); + return ResponseEntity.ok(screeningListResponse); } @PostMapping - public ResponseEntity createNewScreening(@PathVariable int id, @RequestBody Screening screening) { - Movie movie = this.movieRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that id was found") - ); + public ResponseEntity> createNewScreening(@PathVariable int id, @RequestBody Screening screening) { + Movie movie = this.movieRepository.findById(id).orElse(null); + if (movie == null) { + this.errorResponse.set("No movie with that id found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } screening.setCreatedAt(LocalDateTime.now()); screening.setUpdatedAt(LocalDateTime.now()); screening.setMovie(movie); - return new ResponseEntity<>(this.screeningRepository.save(screening), HttpStatus.CREATED); + + if (screening.getScreenNumber() <= 0 || screening.getCapacity() <= 0 || screening.getStartsAt() == null) { + this.errorResponse.set("Could not create a new screening, please check all fields are correct"); + return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); + } + this.screeningResponse.set(this.screeningRepository.save(screening)); + return new ResponseEntity<>(screeningResponse, HttpStatus.CREATED); } @DeleteMapping("{screening_id}") - public ResponseEntity deleteScreening(@PathVariable int id) { - Screening screeningToDelete = this.screeningRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that id was found") - ); + public ResponseEntity> deleteScreening(@PathVariable int id) { + Screening screeningToDelete = this.screeningRepository.findById(id).orElse(null); + if (screeningToDelete == null) { + errorResponse.set("No screening with that id was found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } this.screeningRepository.delete(screeningToDelete); - return ResponseEntity.ok(screeningToDelete); + this.screeningResponse.set(screeningToDelete); + return ResponseEntity.ok(screeningResponse); } } \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java b/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java index 9198e2bb..78d69de2 100644 --- a/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java +++ b/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java @@ -2,6 +2,7 @@ import com.booleanuk.api.cinema.customers.Customer; import com.booleanuk.api.cinema.screenings.Screening; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIncludeProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java b/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java index ab5f28bc..bf929749 100644 --- a/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java +++ b/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java @@ -2,13 +2,16 @@ import com.booleanuk.api.cinema.customers.Customer; import com.booleanuk.api.cinema.customers.CustomerRepository; +import com.booleanuk.api.cinema.responses.ErrorResponse; +import com.booleanuk.api.cinema.responses.Response; +import com.booleanuk.api.cinema.responses.TicketListResponse; +import com.booleanuk.api.cinema.responses.TicketResponse; import com.booleanuk.api.cinema.screenings.Screening; import com.booleanuk.api.cinema.screenings.ScreeningRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; import java.util.List; @@ -25,44 +28,56 @@ public class TicketController { @Autowired private CustomerRepository customerRepository; + private ErrorResponse errorResponse = new ErrorResponse(); + private TicketResponse ticketResponse = new TicketResponse(); + private TicketListResponse ticketListResponse = new TicketListResponse(); + @GetMapping - public ResponseEntity> getAllTickets(@PathVariable int customerId, @PathVariable int screeningId) { + public ResponseEntity> getAllTickets(@PathVariable int customerId, @PathVariable int screeningId) { Customer customer = this.customerRepository.findById(customerId).orElse(null); Screening screening = this.screeningRepository.findById(screeningId).orElse(null); if (customer == null || screening == null) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No ticket found for the customer and screening with those ids"); + this.errorResponse.set("No ticket found for the customer and screening with those ids"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); } List tickets = this.ticketRepository.findByCustomerAndScreening(customer, screening); //findALL? - return ResponseEntity.ok(tickets); + this.ticketListResponse.set(tickets); + return ResponseEntity.ok(ticketListResponse); } @PostMapping - public ResponseEntity createNewTicket(@PathVariable int customerId, @PathVariable int screeningId, @RequestBody Ticket ticket) { + public ResponseEntity> createNewTicket(@PathVariable int customerId, @PathVariable int screeningId, @RequestBody Ticket ticket) { Customer customer = this.customerRepository.findById(customerId).orElse(null); Screening screening = this.screeningRepository.findById(screeningId).orElse(null); if (customer == null || screening == null) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer or screening with those ids found"); + this.errorResponse.set("No customer or screening with those ids found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); } ticket.setCreatedAt(LocalDateTime.now()); ticket.setUpdatedAt(LocalDateTime.now()); ticket.setCustomer(customer); ticket.setScreening(screening); - return new ResponseEntity<>(this.ticketRepository.save(ticket), HttpStatus.CREATED); + this.ticketRepository.save(ticket); + this.ticketResponse.set(ticket); + return new ResponseEntity<>(ticketResponse, HttpStatus.CREATED); } @DeleteMapping("{ticket_id}") - public ResponseEntity deleteTicket(@PathVariable int id) { - Ticket ticketToDelete = this.ticketRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No ticket with that id was found") - ); + public ResponseEntity> deleteTicket(@PathVariable int id) { + Ticket ticketToDelete = this.ticketRepository.findById(id).orElse(null); + if (ticketToDelete == null) { + errorResponse.set("No ticket with that id was found"); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } this.ticketRepository.delete(ticketToDelete); - return ResponseEntity.ok(ticketToDelete); + this.ticketResponse.set(ticketToDelete); + return ResponseEntity.ok(ticketResponse); } } \ No newline at end of file