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..bbc827ba --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/customers/Customer.java @@ -0,0 +1,51 @@ +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; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.List; + + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "customers") +@JsonIgnoreProperties({"tickets"}) +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; + + @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; + 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..28acea2c --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/customers/CustomerController.java @@ -0,0 +1,85 @@ +package com.booleanuk.api.cinema.customers; + +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 java.time.LocalDateTime; + +@RestController +@RequestMapping("customers") +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() { + this.customerListResponse.set(this.customerRepository.findAll()); + return ResponseEntity.ok(customerListResponse); + } + + @PostMapping + public ResponseEntity> createCustomer(@RequestBody Customer customer) { + customer.setCreatedAt(LocalDateTime.now()); + customer.setUpdatedAt(LocalDateTime.now()); + 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).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).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()); + 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).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); + this.customerResponse.set(customerToDelete); + return ResponseEntity.ok(customerResponse); + } + +} \ 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..d12d707c --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/movies/MovieController.java @@ -0,0 +1,98 @@ +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 java.time.LocalDateTime; + +@RestController +@RequestMapping("movies") +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() { + this.movieListResponse.set(this.movieRepository.findAll()); + return ResponseEntity.ok(movieListResponse); + } + + @PostMapping + public ResponseEntity> createMovie(@RequestBody Movie movie) { + movie.setCreatedAt(LocalDateTime.now()); + movie.setUpdatedAt(LocalDateTime.now()); + 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).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).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()); + 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).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); + this.movieResponse.set(movieToDelete); + return ResponseEntity.ok(movieResponse); + } + + + +} \ 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/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 { +} 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..f427936e --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/screenings/Screening.java @@ -0,0 +1,63 @@ +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.JsonIgnoreProperties; +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 = "screenings") +@JsonIgnoreProperties({"tickets"}) +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; + + @OneToMany(mappedBy = "screening", cascade = CascadeType.REMOVE) + @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; + 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..8e626202 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/screenings/ScreeningController.java @@ -0,0 +1,75 @@ +package com.booleanuk.api.cinema.screenings; + +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 java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("movies/{id}/screenings") +public class ScreeningController { + @Autowired + private ScreeningRepository screeningRepository; + + @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).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); + this.screeningListResponse.set(screenings); + return ResponseEntity.ok(screeningListResponse); + } + + @PostMapping + 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); + + 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).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); + this.screeningResponse.set(screeningToDelete); + return ResponseEntity.ok(screeningResponse); + } + +} \ 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); +} 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..78d69de2 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/tickets/Ticket.java @@ -0,0 +1,49 @@ +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.JsonIgnoreProperties; +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 id, 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..bf929749 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/tickets/TicketController.java @@ -0,0 +1,83 @@ +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.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 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; + + 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) { + Customer customer = this.customerRepository.findById(customerId).orElse(null); + + Screening screening = this.screeningRepository.findById(screeningId).orElse(null); + + if (customer == null || screening == null) { + 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? + this.ticketListResponse.set(tickets); + return ResponseEntity.ok(ticketListResponse); + } + + @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) { + 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); + 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).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); + this.ticketResponse.set(ticketToDelete); + return ResponseEntity.ok(ticketResponse); + } + +} \ 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); +}