From 0e43044424d9ecac0eba3b8dcef5ea9d576b59dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 09:09:55 +0100 Subject: [PATCH 01/18] Create all classes and add fields to model classes --- build.gradle | 17 ++- .../java/com/booleanuk/api/cinema/Main.java | 11 ++ .../cinema/controller/CustomerController.java | 4 + .../cinema/controller/MovieController.java | 4 + .../controller/ScreeningController.java | 4 + .../cinema/controller/TicketController.java | 4 + .../booleanuk/api/cinema/model/Customer.java | 92 ++++++++++++++++ .../com/booleanuk/api/cinema/model/Movie.java | 99 +++++++++++++++++ .../booleanuk/api/cinema/model/Screening.java | 104 ++++++++++++++++++ .../booleanuk/api/cinema/model/Ticket.java | 4 + .../cinema/repository/CustomerRepository.java | 4 + .../cinema/repository/MovieRepository.java | 4 + .../repository/ScreeningRepository.java | 4 + .../cinema/repository/TicketRepository.java | 4 + 14 files changed, 355 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/booleanuk/api/cinema/Main.java create mode 100644 src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/controller/MovieController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/controller/TicketController.java create mode 100644 src/main/java/com/booleanuk/api/cinema/model/Customer.java create mode 100644 src/main/java/com/booleanuk/api/cinema/model/Movie.java create mode 100644 src/main/java/com/booleanuk/api/cinema/model/Screening.java create mode 100644 src/main/java/com/booleanuk/api/cinema/model/Ticket.java create mode 100644 src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java create mode 100644 src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java create mode 100644 src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java create mode 100644 src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java diff --git a/build.gradle b/build.gradle index 3d7f7607..f34a107e 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,12 +26,15 @@ 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' +// runtimeOnly 'org.postgresql:postgresql' + implementation 'org.postgresql:postgresql:42.7.4' +// annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { useJUnitPlatform() -} \ No newline at end of file +} 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/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java new file mode 100644 index 00000000..9543fffb --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.controller; + +public class CustomerController { +} diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java new file mode 100644 index 00000000..e1056afd --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.controller; + +public class MovieController { +} diff --git a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java new file mode 100644 index 00000000..dcc3a3b9 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.controller; + +public class ScreeningController { +} diff --git a/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java b/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java new file mode 100644 index 00000000..e753f786 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.controller; + +public class TicketController { +} diff --git a/src/main/java/com/booleanuk/api/cinema/model/Customer.java b/src/main/java/com/booleanuk/api/cinema/model/Customer.java new file mode 100644 index 00000000..3803cc23 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/model/Customer.java @@ -0,0 +1,92 @@ +package com.booleanuk.api.cinema.model; + +import jakarta.persistence.*; + +import java.time.LocalDateTime; + +@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(int id, String name, String email, String phone, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.id = id; + this.name = name; + this.email = email; + this.phone = phone; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Customer(String name, String email, String phone, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.name = name; + this.email = email; + this.phone = phone; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Customer(int id) { + this.id = id; + } + + public Customer() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } +} diff --git a/src/main/java/com/booleanuk/api/cinema/model/Movie.java b/src/main/java/com/booleanuk/api/cinema/model/Movie.java new file mode 100644 index 00000000..81837ad1 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/model/Movie.java @@ -0,0 +1,99 @@ +package com.booleanuk.api.cinema.model; + +import jakarta.persistence.*; + +import java.time.LocalDateTime; + +@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; + + public Movie(int id, String title, String rating, String description, int runtimeMins, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.id = id; + this.title = title; + this.rating = rating; + this.description = description; + this.runtimeMins = runtimeMins; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Movie(String title, String rating, String description, int runtimeMins, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.title = title; + this.rating = rating; + this.description = description; + this.runtimeMins = runtimeMins; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Movie(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getRating() { + return rating; + } + + public void setRating(String rating) { + this.rating = rating; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public int getRuntimeMins() { + return runtimeMins; + } + + public void setRuntimeMins(int runtimeMins) { + this.runtimeMins = runtimeMins; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } +} diff --git a/src/main/java/com/booleanuk/api/cinema/model/Screening.java b/src/main/java/com/booleanuk/api/cinema/model/Screening.java new file mode 100644 index 00000000..104f1cf3 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/model/Screening.java @@ -0,0 +1,104 @@ +package com.booleanuk.api.cinema.model; + +import jakarta.persistence.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name="screenings") +public class Screening { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private String id; + + @ManyToOne + private Movie movie; + + @Column private int screenNumber; + @Column private int capacity; + @Column private LocalDateTime startsAt; + @Column private LocalDateTime createdAt; + @Column private LocalDateTime updatedAt; + + public Screening(String id, Movie movie, int screenNumber, int capacity, LocalDateTime startsAt, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.id = id; + this.movie = movie; + this.screenNumber = screenNumber; + this.capacity = capacity; + this.startsAt = startsAt; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Screening(Movie movie, int screenNumber, int capacity, LocalDateTime startsAt, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.movie = movie; + this.screenNumber = screenNumber; + this.capacity = capacity; + this.startsAt = startsAt; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Screening(String id) { + this.id = id; + } + + public Screening() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Movie getMovie() { + return movie; + } + + public void setMovie(Movie movie) { + this.movie = movie; + } + + public int getScreenNumber() { + return screenNumber; + } + + public void setScreenNumber(int screenNumber) { + this.screenNumber = screenNumber; + } + + public int getCapacity() { + return capacity; + } + + public void setCapacity(int capacity) { + this.capacity = capacity; + } + + public LocalDateTime getStartsAt() { + return startsAt; + } + + public void setStartsAt(LocalDateTime startsAt) { + this.startsAt = startsAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } +} diff --git a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java new file mode 100644 index 00000000..8118ea54 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.model; + +public class Ticket { +} diff --git a/src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java new file mode 100644 index 00000000..fadefbad --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.repository; + +public interface CustomerRepository { +} diff --git a/src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java new file mode 100644 index 00000000..1a35f9d1 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.repository; + +public interface MovieRepository { +} diff --git a/src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java new file mode 100644 index 00000000..4ccf2023 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.repository; + +public interface ScreeningRepository { +} diff --git a/src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java new file mode 100644 index 00000000..f3d6e904 --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java @@ -0,0 +1,4 @@ +package com.booleanuk.api.cinema.repository; + +public interface TicketRepository { +} From fb8ef8ad0d52dad9b80810ff24ceccb518d1f85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 09:18:48 +0100 Subject: [PATCH 02/18] Extend repositories --- .../booleanuk/api/cinema/repository/CustomerRepository.java | 5 ++++- .../com/booleanuk/api/cinema/repository/MovieRepository.java | 5 ++++- .../booleanuk/api/cinema/repository/ScreeningRepository.java | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java index fadefbad..5ddf67bc 100644 --- a/src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java +++ b/src/main/java/com/booleanuk/api/cinema/repository/CustomerRepository.java @@ -1,4 +1,7 @@ package com.booleanuk.api.cinema.repository; -public interface CustomerRepository { +import com.booleanuk.api.cinema.model.Customer; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CustomerRepository extends JpaRepository { } diff --git a/src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java index 1a35f9d1..c689e162 100644 --- a/src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java +++ b/src/main/java/com/booleanuk/api/cinema/repository/MovieRepository.java @@ -1,4 +1,7 @@ package com.booleanuk.api.cinema.repository; -public interface MovieRepository { +import com.booleanuk.api.cinema.model.Movie; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MovieRepository extends JpaRepository { } diff --git a/src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java index 4ccf2023..1235edbd 100644 --- a/src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java +++ b/src/main/java/com/booleanuk/api/cinema/repository/ScreeningRepository.java @@ -1,4 +1,7 @@ package com.booleanuk.api.cinema.repository; -public interface ScreeningRepository { +import com.booleanuk.api.cinema.model.Screening; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ScreeningRepository extends JpaRepository { } From af0acabb51655698c9f4d766c3aeb86ef2d0a3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 09:42:32 +0100 Subject: [PATCH 03/18] Add constructors without createdAt --- .../booleanuk/api/cinema/model/Customer.java | 17 ++++++++++++++ .../com/booleanuk/api/cinema/model/Movie.java | 19 +++++++++++++++ .../booleanuk/api/cinema/model/Screening.java | 23 +++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/src/main/java/com/booleanuk/api/cinema/model/Customer.java b/src/main/java/com/booleanuk/api/cinema/model/Customer.java index 3803cc23..e231e45c 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Customer.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Customer.java @@ -35,6 +35,23 @@ public Customer(String name, String email, String phone, LocalDateTime createdAt this.updatedAt = updatedAt; } + public Customer(int id, String name, String email, String phone) { + this.id = id; + this.name = name; + this.email = email; + this.phone = phone; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + public Customer(String name, String email, String phone) { + this.name = name; + this.email = email; + this.phone = phone; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + public Customer(int id) { this.id = id; } diff --git a/src/main/java/com/booleanuk/api/cinema/model/Movie.java b/src/main/java/com/booleanuk/api/cinema/model/Movie.java index 81837ad1..512fb4c7 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Movie.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Movie.java @@ -37,6 +37,25 @@ public Movie(String title, String rating, String description, int runtimeMins, L this.updatedAt = updatedAt; } + public Movie(int id, String title, String rating, String description, int runtimeMins) { + this.id = id; + this.title = title; + this.rating = rating; + this.description = description; + this.runtimeMins = runtimeMins; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + public Movie(String title, String rating, String description, int runtimeMins) { + this.title = title; + this.rating = rating; + this.description = description; + this.runtimeMins = runtimeMins; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + public Movie(int id) { this.id = id; } diff --git a/src/main/java/com/booleanuk/api/cinema/model/Screening.java b/src/main/java/com/booleanuk/api/cinema/model/Screening.java index 104f1cf3..ea0374b4 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Screening.java @@ -39,6 +39,25 @@ public Screening(Movie movie, int screenNumber, int capacity, LocalDateTime star this.updatedAt = updatedAt; } + public Screening(String id, Movie movie, int screenNumber, int capacity, LocalDateTime startsAt) { + this.id = id; + this.movie = movie; + this.screenNumber = screenNumber; + this.capacity = capacity; + this.startsAt = startsAt; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + public Screening(Movie movie, int screenNumber, int capacity, LocalDateTime startsAt) { + this.movie = movie; + this.screenNumber = screenNumber; + this.capacity = capacity; + this.startsAt = startsAt; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + public Screening(String id) { this.id = id; } @@ -101,4 +120,8 @@ public LocalDateTime getUpdatedAt() { public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } + + public int getMovieId() { + return this.movie.getId(); + } } From 0d220dc3e51d7e5c3ea886ce4dc97c50b48b184f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 09:43:07 +0100 Subject: [PATCH 04/18] Implement get all mappings --- .../cinema/controller/CustomerController.java | 21 +++++++++++ .../cinema/controller/MovieController.java | 21 +++++++++++ .../controller/ScreeningController.java | 35 +++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 9543fffb..1372be97 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -1,4 +1,25 @@ package com.booleanuk.api.cinema.controller; +import com.booleanuk.api.cinema.model.Customer; +import com.booleanuk.api.cinema.repository.CustomerRepository; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/customers") public class CustomerController { + private CustomerRepository customerRepository; + + public CustomerController(CustomerRepository customerRepository) { + this.customerRepository = customerRepository; + } + + @GetMapping + public ResponseEntity> getAll() { + return ResponseEntity.ok(customerRepository.findAll()); + } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index e1056afd..c32076d8 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -1,4 +1,25 @@ package com.booleanuk.api.cinema.controller; +import com.booleanuk.api.cinema.model.Movie; +import com.booleanuk.api.cinema.repository.MovieRepository; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/movies") public class MovieController { + private MovieRepository movieRepository; + + public MovieController(MovieRepository movieRepository) { + this.movieRepository = movieRepository; + } + + @GetMapping + public ResponseEntity> getAll() { + return ResponseEntity.ok(movieRepository.findAll()); + } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java index dcc3a3b9..d903741c 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java @@ -1,4 +1,39 @@ package com.booleanuk.api.cinema.controller; +import com.booleanuk.api.cinema.model.Movie; +import com.booleanuk.api.cinema.model.Screening; +import com.booleanuk.api.cinema.repository.MovieRepository; +import com.booleanuk.api.cinema.repository.ScreeningRepository; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; + +@RestController +@RequestMapping("/movies/{id}/screenings") public class ScreeningController { + ScreeningRepository screeningRepository; + MovieRepository movieRepository; + + public ScreeningController(ScreeningRepository screeningRepository, MovieRepository movieRepository) { + this.screeningRepository = screeningRepository; + this.movieRepository = movieRepository; + } + + @GetMapping + public ResponseEntity> getAll(@PathVariable(name="id") int movieId) { + Movie movie = movieRepository.findById(movieId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No book with that ID was found.") + ); + + // maybe findAll(...) can also filter + return ResponseEntity.ok(screeningRepository.findAll().stream().filter( + s -> s.getMovieId() == movie.getId() + ).toList()); + } } From c8a86fce9eeaca5767447f2b7dd0142e89c89d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 10:18:30 +0100 Subject: [PATCH 05/18] Make sure timestamps are added --- .../com/booleanuk/api/cinema/model/Customer.java | 4 ++++ .../com/booleanuk/api/cinema/model/Movie.java | 7 +++++++ .../booleanuk/api/cinema/model/Screening.java | 16 ++++++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/model/Customer.java b/src/main/java/com/booleanuk/api/cinema/model/Customer.java index e231e45c..b3e96be2 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Customer.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Customer.java @@ -54,9 +54,13 @@ public Customer(String name, String email, String phone) { public Customer(int id) { this.id = id; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); } public Customer() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); } public int getId() { diff --git a/src/main/java/com/booleanuk/api/cinema/model/Movie.java b/src/main/java/com/booleanuk/api/cinema/model/Movie.java index 512fb4c7..e76b3fc3 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Movie.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Movie.java @@ -58,6 +58,13 @@ public Movie(String title, String rating, String description, int runtimeMins) { public Movie(int id) { this.id = id; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + public Movie() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); } public int getId() { diff --git a/src/main/java/com/booleanuk/api/cinema/model/Screening.java b/src/main/java/com/booleanuk/api/cinema/model/Screening.java index ea0374b4..70fcaea3 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Screening.java @@ -9,7 +9,7 @@ public class Screening { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private String id; + private int id; @ManyToOne private Movie movie; @@ -20,7 +20,7 @@ public class Screening { @Column private LocalDateTime createdAt; @Column private LocalDateTime updatedAt; - public Screening(String id, Movie movie, int screenNumber, int capacity, LocalDateTime startsAt, LocalDateTime createdAt, LocalDateTime updatedAt) { + public Screening(int id, Movie movie, int screenNumber, int capacity, LocalDateTime startsAt, LocalDateTime createdAt, LocalDateTime updatedAt) { this.id = id; this.movie = movie; this.screenNumber = screenNumber; @@ -39,7 +39,7 @@ public Screening(Movie movie, int screenNumber, int capacity, LocalDateTime star this.updatedAt = updatedAt; } - public Screening(String id, Movie movie, int screenNumber, int capacity, LocalDateTime startsAt) { + public Screening(int id, Movie movie, int screenNumber, int capacity, LocalDateTime startsAt) { this.id = id; this.movie = movie; this.screenNumber = screenNumber; @@ -58,18 +58,22 @@ public Screening(Movie movie, int screenNumber, int capacity, LocalDateTime star this.updatedAt = LocalDateTime.now(); } - public Screening(String id) { + public Screening(int id) { this.id = id; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); } public Screening() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); } - public String getId() { + public int getId() { return id; } - public void setId(String id) { + public void setId(int id) { this.id = id; } From a73b61bed3fd7baf869ad9cf4c84d874a9e29f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 10:41:27 +0100 Subject: [PATCH 06/18] Add getOne endpoints --- .../cinema/controller/CustomerController.java | 10 +++++++ .../cinema/controller/MovieController.java | 10 +++++++ .../controller/ScreeningController.java | 27 +++++++++++++++---- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 1372be97..6fd27144 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -2,10 +2,13 @@ import com.booleanuk.api.cinema.model.Customer; import com.booleanuk.api.cinema.repository.CustomerRepository; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import java.util.List; @@ -18,6 +21,13 @@ public CustomerController(CustomerRepository customerRepository) { this.customerRepository = customerRepository; } + @GetMapping("/{id}") + public ResponseEntity getOne(@PathVariable int id) { + return ResponseEntity.ok(customerRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") + )); + } + @GetMapping public ResponseEntity> getAll() { return ResponseEntity.ok(customerRepository.findAll()); diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index c32076d8..fef7806d 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -2,10 +2,13 @@ import com.booleanuk.api.cinema.model.Movie; import com.booleanuk.api.cinema.repository.MovieRepository; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import java.util.List; @@ -18,6 +21,13 @@ public MovieController(MovieRepository movieRepository) { this.movieRepository = movieRepository; } + @GetMapping("/{id}") + public ResponseEntity getOne(@PathVariable int id) { + return ResponseEntity.ok(movieRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") + )); + } + @GetMapping public ResponseEntity> getAll() { return ResponseEntity.ok(movieRepository.findAll()); diff --git a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java index d903741c..74a2f711 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java @@ -6,12 +6,10 @@ import com.booleanuk.api.cinema.repository.ScreeningRepository; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; +import java.time.LocalDateTime; import java.util.List; @RestController @@ -25,10 +23,29 @@ public ScreeningController(ScreeningRepository screeningRepository, MovieReposit this.movieRepository = movieRepository; } + @PostMapping + public ResponseEntity create(@PathVariable int movieId, @RequestBody Screening screening) { + Movie movie = movieRepository.findById(movieId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") + ); + screening.setMovie(movie); + screening.setCreatedAt(LocalDateTime.now()); + screening.setUpdatedAt(LocalDateTime.now()); + return new ResponseEntity<>(screeningRepository.save(screening), HttpStatus.CREATED); + } + + // Works, but it's weird to have to add a movie id + @GetMapping("/{s_id}") + public ResponseEntity getOne(@PathVariable(name="id") int id, @PathVariable(name="s_id") int s_id) { + return ResponseEntity.ok(screeningRepository.findById(s_id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that ID was found.") + )); + } + @GetMapping public ResponseEntity> getAll(@PathVariable(name="id") int movieId) { Movie movie = movieRepository.findById(movieId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No book with that ID was found.") + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") ); // maybe findAll(...) can also filter From 8a90adc7b6e7c6feaa8f9477aae67cabfa68fa4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 10:49:48 +0100 Subject: [PATCH 07/18] Refactor some screening endpoints to MovieController --- .../cinema/controller/MovieController.java | 35 +++++++++++++++--- .../controller/ScreeningController.java | 36 +++---------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index fef7806d..72a87d15 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -1,24 +1,26 @@ package com.booleanuk.api.cinema.controller; import com.booleanuk.api.cinema.model.Movie; +import com.booleanuk.api.cinema.model.Screening; import com.booleanuk.api.cinema.repository.MovieRepository; +import com.booleanuk.api.cinema.repository.ScreeningRepository; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +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 { private MovieRepository movieRepository; + private ScreeningRepository screeningRepository; - public MovieController(MovieRepository movieRepository) { + public MovieController(MovieRepository movieRepository, ScreeningRepository screeningRepository) { this.movieRepository = movieRepository; + this.screeningRepository = screeningRepository; } @GetMapping("/{id}") @@ -32,4 +34,27 @@ public ResponseEntity getOne(@PathVariable int id) { public ResponseEntity> getAll() { return ResponseEntity.ok(movieRepository.findAll()); } + + @PostMapping("{id}/screenings") + public ResponseEntity create(@PathVariable int movieId, @RequestBody Screening screening) { + Movie movie = movieRepository.findById(movieId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") + ); + screening.setMovie(movie); + screening.setCreatedAt(LocalDateTime.now()); + screening.setUpdatedAt(LocalDateTime.now()); + return new ResponseEntity<>(screeningRepository.save(screening), HttpStatus.CREATED); + } + + @GetMapping("/{id}/screenings") + public ResponseEntity> getAll(@PathVariable(name="id") int movieId) { + Movie movie = movieRepository.findById(movieId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") + ); + + // maybe findAll(...) can also filter + return ResponseEntity.ok(screeningRepository.findAll().stream().filter( + s -> s.getMovieId() == movie.getId() + ).toList()); + } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java index 74a2f711..665e41a2 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java @@ -1,6 +1,5 @@ package com.booleanuk.api.cinema.controller; -import com.booleanuk.api.cinema.model.Movie; import com.booleanuk.api.cinema.model.Screening; import com.booleanuk.api.cinema.repository.MovieRepository; import com.booleanuk.api.cinema.repository.ScreeningRepository; @@ -9,11 +8,8 @@ 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") +@RequestMapping("/screenings") public class ScreeningController { ScreeningRepository screeningRepository; MovieRepository movieRepository; @@ -23,34 +19,10 @@ public ScreeningController(ScreeningRepository screeningRepository, MovieReposit this.movieRepository = movieRepository; } - @PostMapping - public ResponseEntity create(@PathVariable int movieId, @RequestBody Screening screening) { - Movie movie = movieRepository.findById(movieId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") - ); - screening.setMovie(movie); - screening.setCreatedAt(LocalDateTime.now()); - screening.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity<>(screeningRepository.save(screening), HttpStatus.CREATED); - } - - // Works, but it's weird to have to add a movie id - @GetMapping("/{s_id}") - public ResponseEntity getOne(@PathVariable(name="id") int id, @PathVariable(name="s_id") int s_id) { - return ResponseEntity.ok(screeningRepository.findById(s_id).orElseThrow( + @GetMapping("/{id}") + public ResponseEntity getOne(@PathVariable(name="id") int id) { + return ResponseEntity.ok(screeningRepository.findById(id).orElseThrow( () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that ID was found.") )); } - - @GetMapping - public ResponseEntity> getAll(@PathVariable(name="id") int movieId) { - Movie movie = movieRepository.findById(movieId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") - ); - - // maybe findAll(...) can also filter - return ResponseEntity.ok(screeningRepository.findAll().stream().filter( - s -> s.getMovieId() == movie.getId() - ).toList()); - } } From ad05ba5df19c1d12df090e4d36b8f30a0c8648ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 11:14:04 +0100 Subject: [PATCH 08/18] Implement create endpoint for screenings --- .../api/cinema/controller/MovieController.java | 2 +- .../booleanuk/api/cinema/model/Screening.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index 72a87d15..d5cc0ec7 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -36,7 +36,7 @@ public ResponseEntity> getAll() { } @PostMapping("{id}/screenings") - public ResponseEntity create(@PathVariable int movieId, @RequestBody Screening screening) { + public ResponseEntity create(@PathVariable(name="id") int movieId, @RequestBody Screening screening) { Movie movie = movieRepository.findById(movieId).orElseThrow( () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") ); diff --git a/src/main/java/com/booleanuk/api/cinema/model/Screening.java b/src/main/java/com/booleanuk/api/cinema/model/Screening.java index 70fcaea3..fe2931a5 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Screening.java @@ -1,5 +1,10 @@ package com.booleanuk.api.cinema.model; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import jakarta.persistence.*; import java.time.LocalDateTime; @@ -16,6 +21,10 @@ public class Screening { @Column private int screenNumber; @Column private int capacity; + +// @JsonDeserialize(using = LocalDateTimeDeserializer.class) +// @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonFormat(shape=JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss[+SS][:SS]") @Column private LocalDateTime startsAt; @Column private LocalDateTime createdAt; @Column private LocalDateTime updatedAt; @@ -58,6 +67,15 @@ public Screening(Movie movie, int screenNumber, int capacity, LocalDateTime star this.updatedAt = LocalDateTime.now(); } + public Screening(int id, int screenNumber, int capacity, LocalDateTime startsAt, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.id = id; + this.screenNumber = screenNumber; + this.capacity = capacity; + this.startsAt = startsAt; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + public Screening(int id) { this.id = id; this.createdAt = LocalDateTime.now(); From 30adff8039a2a30c557c8bf8e73a3e4fb9111278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 11:20:25 +0100 Subject: [PATCH 09/18] Implement create endpoints for movies and customers --- .../api/cinema/controller/CustomerController.java | 10 ++++++---- .../api/cinema/controller/MovieController.java | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 6fd27144..da29b4db 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -4,10 +4,7 @@ import com.booleanuk.api.cinema.repository.CustomerRepository; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; import java.util.List; @@ -21,6 +18,11 @@ public CustomerController(CustomerRepository customerRepository) { this.customerRepository = customerRepository; } + @PostMapping + public ResponseEntity create(@RequestBody Customer customer) { + return new ResponseEntity<>(customerRepository.save(customer), HttpStatus.CREATED); + } + @GetMapping("/{id}") public ResponseEntity getOne(@PathVariable int id) { return ResponseEntity.ok(customerRepository.findById(id).orElseThrow( diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index d5cc0ec7..fa15d0e8 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -23,6 +23,11 @@ public MovieController(MovieRepository movieRepository, ScreeningRepository scre this.screeningRepository = screeningRepository; } + @PostMapping + public ResponseEntity create(@RequestBody Movie movie) { + return new ResponseEntity<>(movieRepository.save(movie), HttpStatus.CREATED); + } + @GetMapping("/{id}") public ResponseEntity getOne(@PathVariable int id) { return ResponseEntity.ok(movieRepository.findById(id).orElseThrow( From 7936719237c2267c9cabe1637894bb74d39098b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 11:31:41 +0100 Subject: [PATCH 10/18] Implement update and delete endpoints for movies and customers --- .../cinema/controller/CustomerController.java | 23 ++++++++++++++++ .../cinema/controller/MovieController.java | 27 +++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index da29b4db..0325dc07 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -1,12 +1,14 @@ package com.booleanuk.api.cinema.controller; import com.booleanuk.api.cinema.model.Customer; +import com.booleanuk.api.cinema.model.Movie; import com.booleanuk.api.cinema.repository.CustomerRepository; 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 @@ -34,4 +36,25 @@ public ResponseEntity getOne(@PathVariable int id) { public ResponseEntity> getAll() { return ResponseEntity.ok(customerRepository.findAll()); } + + @PutMapping("/{id}") + public ResponseEntity update(@PathVariable int id, @RequestBody Customer customer) { + Customer customerToUpdate = 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<>(customerRepository.save(customerToUpdate), HttpStatus.CREATED); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteCustomer(@PathVariable int id) { + Customer customer = customerRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") + ); + customerRepository.deleteById(id); + return ResponseEntity.ok(customer); + } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index fa15d0e8..df85bec1 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -1,5 +1,6 @@ package com.booleanuk.api.cinema.controller; +import com.booleanuk.api.cinema.model.Customer; import com.booleanuk.api.cinema.model.Movie; import com.booleanuk.api.cinema.model.Screening; import com.booleanuk.api.cinema.repository.MovieRepository; @@ -24,7 +25,7 @@ public MovieController(MovieRepository movieRepository, ScreeningRepository scre } @PostMapping - public ResponseEntity create(@RequestBody Movie movie) { + public ResponseEntity createMovie(@RequestBody Movie movie) { return new ResponseEntity<>(movieRepository.save(movie), HttpStatus.CREATED); } @@ -41,7 +42,7 @@ public ResponseEntity> getAll() { } @PostMapping("{id}/screenings") - public ResponseEntity create(@PathVariable(name="id") int movieId, @RequestBody Screening screening) { + public ResponseEntity createScreening(@PathVariable(name="id") int movieId, @RequestBody Screening screening) { Movie movie = movieRepository.findById(movieId).orElseThrow( () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") ); @@ -62,4 +63,26 @@ public ResponseEntity> getAll(@PathVariable(name="id") int movie s -> s.getMovieId() == movie.getId() ).toList()); } + + @PutMapping("/{id}") + public ResponseEntity updateMovie(@PathVariable int id, @RequestBody Movie movie) { + Movie movieToUpdate = 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<>(movieRepository.save(movieToUpdate), HttpStatus.CREATED); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteMovie(@PathVariable int id) { + Movie movie = movieRepository.findById(id).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") + ); + movieRepository.deleteById(id); + return ResponseEntity.ok(movie); + } } From c0951024eb7be5e2d2b31458017f0578cdd38cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 11:36:03 +0100 Subject: [PATCH 11/18] Create fields for Ticket --- .../cinema/controller/CustomerController.java | 1 - .../booleanuk/api/cinema/model/Screening.java | 4 - .../booleanuk/api/cinema/model/Ticket.java | 97 +++++++++++++++++++ .../cinema/repository/TicketRepository.java | 5 +- 4 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 0325dc07..5cd2e741 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -1,7 +1,6 @@ package com.booleanuk.api.cinema.controller; import com.booleanuk.api.cinema.model.Customer; -import com.booleanuk.api.cinema.model.Movie; import com.booleanuk.api.cinema.repository.CustomerRepository; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/com/booleanuk/api/cinema/model/Screening.java b/src/main/java/com/booleanuk/api/cinema/model/Screening.java index fe2931a5..27d89496 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Screening.java @@ -1,10 +1,6 @@ package com.booleanuk.api.cinema.model; import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; -import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import jakarta.persistence.*; import java.time.LocalDateTime; diff --git a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java index 8118ea54..aefe147d 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java @@ -1,4 +1,101 @@ package com.booleanuk.api.cinema.model; +import jakarta.persistence.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name="tickets") public class Ticket { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @ManyToOne + private Customer customer; + + @ManyToOne + private Screening screening; + + @Column int numSeats; + @Column LocalDateTime createdAt; + @Column LocalDateTime updatedAt; + + public Ticket(int id, Customer customer, Screening screening, int numSeats, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.id = id; + this.customer = customer; + this.screening = screening; + this.numSeats = numSeats; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Ticket(Customer customer, Screening screening, int numSeats, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.customer = customer; + this.screening = screening; + this.numSeats = numSeats; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Ticket(int numSeats, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.numSeats = numSeats; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Ticket(int id) { + this.id = id; + } + + public Ticket() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public Screening getScreening() { + return screening; + } + + public void setScreening(Screening screening) { + this.screening = screening; + } + + public int getNumSeats() { + return numSeats; + } + + public void setNumSeats(int numSeats) { + this.numSeats = numSeats; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } } diff --git a/src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java b/src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java index f3d6e904..ee891c02 100644 --- a/src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java +++ b/src/main/java/com/booleanuk/api/cinema/repository/TicketRepository.java @@ -1,4 +1,7 @@ package com.booleanuk.api.cinema.repository; -public interface TicketRepository { +import com.booleanuk.api.cinema.model.Ticket; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TicketRepository extends JpaRepository { } From f5b65a3d3c217c22acefeba731eaaf5a1d0cd06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 13:12:44 +0100 Subject: [PATCH 12/18] Create endpoints for getting all tickets --- .../cinema/controller/CustomerController.java | 26 +++++++++++++++++- .../cinema/controller/MovieController.java | 1 - .../cinema/controller/TicketController.java | 27 +++++++++++++++++++ .../booleanuk/api/cinema/model/Ticket.java | 8 ++++++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 5cd2e741..ecefb8df 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -1,7 +1,12 @@ package com.booleanuk.api.cinema.controller; import com.booleanuk.api.cinema.model.Customer; +import com.booleanuk.api.cinema.model.Movie; +import com.booleanuk.api.cinema.model.Screening; +import com.booleanuk.api.cinema.model.Ticket; import com.booleanuk.api.cinema.repository.CustomerRepository; +import com.booleanuk.api.cinema.repository.ScreeningRepository; +import com.booleanuk.api.cinema.repository.TicketRepository; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -14,9 +19,13 @@ @RequestMapping("/customers") public class CustomerController { private CustomerRepository customerRepository; + private TicketRepository ticketRepository; + private ScreeningRepository screeningRepository; - public CustomerController(CustomerRepository customerRepository) { + public CustomerController(CustomerRepository customerRepository, TicketRepository ticketRepository, ScreeningRepository screeningRepository) { this.customerRepository = customerRepository; + this.ticketRepository = ticketRepository; + this.screeningRepository = screeningRepository; } @PostMapping @@ -56,4 +65,19 @@ public ResponseEntity deleteCustomer(@PathVariable int id) { customerRepository.deleteById(id); return ResponseEntity.ok(customer); } + + @GetMapping("/{c_id}/screenings/{s_id}") + public ResponseEntity> getAllTickets(@PathVariable(name="c_id") int customerId, @PathVariable(name="s_id") int screeningId) { + Customer customer = customerRepository.findById(customerId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") + ); + + Screening screening = screeningRepository.findById(screeningId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that ID was found.") + ); + + return ResponseEntity.ok(ticketRepository.findAll().stream().filter( + t -> t.getCustomerId() == customer.getId() && t.getScreeningId() == screening.getId() + ).toList()); + } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index df85bec1..834194fd 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -1,6 +1,5 @@ package com.booleanuk.api.cinema.controller; -import com.booleanuk.api.cinema.model.Customer; import com.booleanuk.api.cinema.model.Movie; import com.booleanuk.api.cinema.model.Screening; import com.booleanuk.api.cinema.repository.MovieRepository; diff --git a/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java b/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java index e753f786..18d164d1 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java @@ -1,4 +1,31 @@ package com.booleanuk.api.cinema.controller; +import com.booleanuk.api.cinema.model.Ticket; +import com.booleanuk.api.cinema.repository.MovieRepository; +import com.booleanuk.api.cinema.repository.ScreeningRepository; +import com.booleanuk.api.cinema.repository.TicketRepository; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/tickets") public class TicketController { + private TicketRepository ticketRepository; + private MovieRepository movieRepository; + private ScreeningRepository screeningRepository; + + public TicketController(TicketRepository ticketRepository, MovieRepository movieRepository, ScreeningRepository screeningRepository) { + this.ticketRepository = ticketRepository; + this.movieRepository = movieRepository; + this.screeningRepository = screeningRepository; + } + + @GetMapping + public ResponseEntity> getAll() { + return ResponseEntity.ok(ticketRepository.findAll()); + } } diff --git a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java index aefe147d..e3ebabc6 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java @@ -98,4 +98,12 @@ public LocalDateTime getUpdatedAt() { public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } + + public int getCustomerId() { + return this.customer.getId(); + } + + public int getScreeningId() { + return this.screening.getId(); + } } From a765066249a378944914cb3107e293d7b61bffc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 13:21:19 +0100 Subject: [PATCH 13/18] Create endpoint for booking a ticket --- .../api/cinema/controller/CustomerController.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index ecefb8df..40ff96d7 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -66,6 +66,21 @@ public ResponseEntity deleteCustomer(@PathVariable int id) { return ResponseEntity.ok(customer); } + @PostMapping("/{c_id}/screenings/{s_id}") + public ResponseEntity bookTicket(@PathVariable(name="c_id") int customerId, @PathVariable(name="s_id") int screeningId, @RequestBody Ticket ticket) { + Customer customer = customerRepository.findById(customerId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") + ); + + Screening screening = screeningRepository.findById(screeningId).orElseThrow( + () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that ID was found.") + ); + + ticket.setCustomer(customer); + ticket.setScreening(screening); + return new ResponseEntity<>(ticketRepository.save(ticket), HttpStatus.CREATED); + } + @GetMapping("/{c_id}/screenings/{s_id}") public ResponseEntity> getAllTickets(@PathVariable(name="c_id") int customerId, @PathVariable(name="s_id") int screeningId) { Customer customer = customerRepository.findById(customerId).orElseThrow( From 540a36958b64c39be4bd7ed7c67fb37ddff88f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 15:58:55 +0100 Subject: [PATCH 14/18] Implement error handling with responses --- .../cinema/controller/CustomerController.java | 90 +++++++++++-------- .../cinema/controller/MovieController.java | 85 +++++++++++------- .../controller/ScreeningController.java | 12 +-- .../cinema/controller/TicketController.java | 6 +- .../booleanuk/api/cinema/model/Screening.java | 6 +- .../booleanuk/api/cinema/model/Ticket.java | 7 ++ .../api/cinema/responses/ErrorResponse.java | 21 +++++ .../api/cinema/responses/Response.java | 39 ++++++++ 8 files changed, 187 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/ErrorResponse.java create mode 100644 src/main/java/com/booleanuk/api/cinema/responses/Response.java diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 40ff96d7..3c34596a 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -1,12 +1,13 @@ package com.booleanuk.api.cinema.controller; import com.booleanuk.api.cinema.model.Customer; -import com.booleanuk.api.cinema.model.Movie; import com.booleanuk.api.cinema.model.Screening; import com.booleanuk.api.cinema.model.Ticket; import com.booleanuk.api.cinema.repository.CustomerRepository; import com.booleanuk.api.cinema.repository.ScreeningRepository; import com.booleanuk.api.cinema.repository.TicketRepository; +import com.booleanuk.api.cinema.responses.ErrorResponse; +import com.booleanuk.api.cinema.responses.Response; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -29,70 +30,87 @@ public CustomerController(CustomerRepository customerRepository, TicketRepositor } @PostMapping - public ResponseEntity create(@RequestBody Customer customer) { - return new ResponseEntity<>(customerRepository.save(customer), HttpStatus.CREATED); + public ResponseEntity> create(@RequestBody Customer customer) { + Customer addedCustomer = customerRepository.save(customer); + if (addedCustomer == null) { + return new ResponseEntity<>(new ErrorResponse("bad request"), HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(new Response<>("success", addedCustomer), HttpStatus.CREATED); } @GetMapping("/{id}") - public ResponseEntity getOne(@PathVariable int id) { - return ResponseEntity.ok(customerRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") - )); + public ResponseEntity> getOne(@PathVariable int id) { +// return ResponseEntity.ok(customerRepository.findById(id).orElseThrow( +// () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") +// )); + Customer customer = customerRepository.findById(id).orElse(null); + if (customer == null) { + ErrorResponse error = new ErrorResponse("not found"); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + Response response = new Response<>(); + response.set(customer); + return ResponseEntity.ok(response); } @GetMapping - public ResponseEntity> getAll() { - return ResponseEntity.ok(customerRepository.findAll()); + public ResponseEntity> getAll() { + return ResponseEntity.ok(new Response<>("success", customerRepository.findAll())); + } @PutMapping("/{id}") - public ResponseEntity update(@PathVariable int id, @RequestBody Customer customer) { - Customer customerToUpdate = customerRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") - ); + public ResponseEntity> update(@PathVariable int id, @RequestBody Customer customer) { + Customer customerToUpdate = customerRepository.findById(id).orElse(null); + if (customerToUpdate == null) { + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + } customerToUpdate.setName(customer.getName()); customerToUpdate.setEmail(customer.getEmail()); customerToUpdate.setPhone(customer.getPhone()); customerToUpdate.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity<>(customerRepository.save(customerToUpdate), HttpStatus.CREATED); + // todo error 400 + return new ResponseEntity<>(new Response<>(customerRepository.save(customerToUpdate)), HttpStatus.CREATED); } @DeleteMapping("/{id}") - public ResponseEntity deleteCustomer(@PathVariable int id) { - Customer customer = customerRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") - ); + public ResponseEntity> deleteCustomer(@PathVariable int id) { + Customer customer = customerRepository.findById(id).orElse(null); + if (customer == null) { + return new ResponseEntity(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + } + customerRepository.deleteById(id); - return ResponseEntity.ok(customer); + return ResponseEntity.ok(new Response<>("success", customer)); } @PostMapping("/{c_id}/screenings/{s_id}") - public ResponseEntity bookTicket(@PathVariable(name="c_id") int customerId, @PathVariable(name="s_id") int screeningId, @RequestBody Ticket ticket) { - Customer customer = customerRepository.findById(customerId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") - ); + public ResponseEntity> bookTicket(@PathVariable(name = "c_id") int customerId, @PathVariable(name = "s_id") int screeningId, @RequestBody Ticket ticket) { + Customer customer = customerRepository.findById(customerId).orElse(null); + Screening screening = screeningRepository.findById(screeningId).orElse(null); - Screening screening = screeningRepository.findById(screeningId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that ID was found.") - ); + if (customer == null || screening == null) { + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + } ticket.setCustomer(customer); ticket.setScreening(screening); - return new ResponseEntity<>(ticketRepository.save(ticket), HttpStatus.CREATED); + ticket.setCreatedAt(LocalDateTime.now()); + ticket.setUpdatedAt(LocalDateTime.now()); + return new ResponseEntity<>(new Response<>("success", ticketRepository.save(ticket)), HttpStatus.CREATED); } @GetMapping("/{c_id}/screenings/{s_id}") - public ResponseEntity> getAllTickets(@PathVariable(name="c_id") int customerId, @PathVariable(name="s_id") int screeningId) { - Customer customer = customerRepository.findById(customerId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No customer with that ID was found.") - ); + public ResponseEntity> getAllTickets(@PathVariable(name = "c_id") int customerId, @PathVariable(name = "s_id") int screeningId) { + Customer customer = customerRepository.findById(customerId).orElse(null); + Screening screening = screeningRepository.findById(screeningId).orElse(null); - Screening screening = screeningRepository.findById(screeningId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that ID was found.") - ); + if (customer == null || screening == null) { + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + } - return ResponseEntity.ok(ticketRepository.findAll().stream().filter( + return new ResponseEntity<>(new Response<>("success", ticketRepository.findAll().stream().filter( t -> t.getCustomerId() == customer.getId() && t.getScreeningId() == screening.getId() - ).toList()); + ).toList()), HttpStatus.OK); } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index 834194fd..2ddf9b5d 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -4,13 +4,13 @@ import com.booleanuk.api.cinema.model.Screening; import com.booleanuk.api.cinema.repository.MovieRepository; import com.booleanuk.api.cinema.repository.ScreeningRepository; +import com.booleanuk.api.cinema.responses.ErrorResponse; +import com.booleanuk.api.cinema.responses.Response; 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") @@ -24,64 +24,81 @@ public MovieController(MovieRepository movieRepository, ScreeningRepository scre } @PostMapping - public ResponseEntity createMovie(@RequestBody Movie movie) { - return new ResponseEntity<>(movieRepository.save(movie), HttpStatus.CREATED); + public ResponseEntity> createMovie(@RequestBody Movie movie) { + Movie createdMovie = movieRepository.save(movie); + if (createdMovie == null) { + return new ResponseEntity<>(new ErrorResponse("bad request"), HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(new Response<>("success", createdMovie), HttpStatus.CREATED); } @GetMapping("/{id}") - public ResponseEntity getOne(@PathVariable int id) { - return ResponseEntity.ok(movieRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") - )); + public ResponseEntity> getOne(@PathVariable int id) { + Movie movie = movieRepository.findById(id).orElse(null); + if (movie == null) { + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(new Response<>("success", movie), HttpStatus.OK); } @GetMapping - public ResponseEntity> getAll() { - return ResponseEntity.ok(movieRepository.findAll()); + public ResponseEntity> getAll() { + return new ResponseEntity<>(new Response<>("success", movieRepository.findAll()), HttpStatus.OK); } @PostMapping("{id}/screenings") - public ResponseEntity createScreening(@PathVariable(name="id") int movieId, @RequestBody Screening screening) { - Movie movie = movieRepository.findById(movieId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") - ); + public ResponseEntity> createScreening(@PathVariable(name = "id") int movieId, @RequestBody Screening screening) { + Movie movie = movieRepository.findById(movieId).orElse(null); + if (movie == null) { + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + } + screening.setMovie(movie); screening.setCreatedAt(LocalDateTime.now()); screening.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity<>(screeningRepository.save(screening), HttpStatus.CREATED); + Screening createdScreening = screeningRepository.save(screening); + + if (createdScreening == null) { + return new ResponseEntity<>(new ErrorResponse("bad request"), HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(new Response<>("success", createdScreening), HttpStatus.CREATED); } @GetMapping("/{id}/screenings") - public ResponseEntity> getAll(@PathVariable(name="id") int movieId) { - Movie movie = movieRepository.findById(movieId).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") - ); - - // maybe findAll(...) can also filter - return ResponseEntity.ok(screeningRepository.findAll().stream().filter( - s -> s.getMovieId() == movie.getId() - ).toList()); + public ResponseEntity> getAllScreenings(@PathVariable(name = "id") int movieId) { + Movie movie = movieRepository.findById(movieId).orElse(null); + if (movie == null) + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + + return new ResponseEntity<>(new Response<>("success", screeningRepository.findAll().stream().filter( + s -> s.getMovieId() == movie.getId()).toList()), HttpStatus.OK); } @PutMapping("/{id}") - public ResponseEntity updateMovie(@PathVariable int id, @RequestBody Movie movie) { - Movie movieToUpdate = 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 = movieRepository.findById(id).orElse(null); + if (movieToUpdate == null) { + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + } + movieToUpdate.setTitle(movie.getTitle()); movieToUpdate.setRating(movie.getRating()); movieToUpdate.setDescription(movie.getDescription()); movieToUpdate.setRuntimeMins(movie.getRuntimeMins()); movieToUpdate.setUpdatedAt(LocalDateTime.now()); - return new ResponseEntity<>(movieRepository.save(movieToUpdate), HttpStatus.CREATED); + + if (movieRepository.save(movieToUpdate) == null) { + return new ResponseEntity<>(new ErrorResponse("bad request"), HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(new Response<>("success", movieToUpdate), HttpStatus.CREATED); } @DeleteMapping("/{id}") - public ResponseEntity deleteMovie(@PathVariable int id) { - Movie movie = movieRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No movie with that ID was found.") - ); + public ResponseEntity> deleteMovie(@PathVariable int id) { + Movie movie = movieRepository.findById(id).orElse(null); + if (movie == null) + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); movieRepository.deleteById(id); - return ResponseEntity.ok(movie); + return ResponseEntity.ok(new Response<>("success", movie)); } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java index 665e41a2..7a33d7b8 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/ScreeningController.java @@ -3,10 +3,11 @@ import com.booleanuk.api.cinema.model.Screening; import com.booleanuk.api.cinema.repository.MovieRepository; import com.booleanuk.api.cinema.repository.ScreeningRepository; +import com.booleanuk.api.cinema.responses.ErrorResponse; +import com.booleanuk.api.cinema.responses.Response; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; @RestController @RequestMapping("/screenings") @@ -20,9 +21,10 @@ public ScreeningController(ScreeningRepository screeningRepository, MovieReposit } @GetMapping("/{id}") - public ResponseEntity getOne(@PathVariable(name="id") int id) { - return ResponseEntity.ok(screeningRepository.findById(id).orElseThrow( - () -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No screening with that ID was found.") - )); + public ResponseEntity> getOne(@PathVariable(name = "id") int id) { + Screening screening = screeningRepository.findById(id).orElse(null); + if (screening == null) + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + return ResponseEntity.ok(new Response<>("success", screening)); } } diff --git a/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java b/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java index 18d164d1..94fa5786 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/TicketController.java @@ -4,6 +4,8 @@ import com.booleanuk.api.cinema.repository.MovieRepository; import com.booleanuk.api.cinema.repository.ScreeningRepository; import com.booleanuk.api.cinema.repository.TicketRepository; +import com.booleanuk.api.cinema.responses.Response; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -25,7 +27,7 @@ public TicketController(TicketRepository ticketRepository, MovieRepository movie } @GetMapping - public ResponseEntity> getAll() { - return ResponseEntity.ok(ticketRepository.findAll()); + public ResponseEntity> getAll() { + return new ResponseEntity<>(new Response<>("success", ticketRepository.findAll()), HttpStatus.OK); } } diff --git a/src/main/java/com/booleanuk/api/cinema/model/Screening.java b/src/main/java/com/booleanuk/api/cinema/model/Screening.java index 27d89496..0e6f5825 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Screening.java @@ -1,6 +1,7 @@ package com.booleanuk.api.cinema.model; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import java.time.LocalDateTime; @@ -13,15 +14,15 @@ public class Screening { private int id; @ManyToOne + @JsonIgnore private Movie movie; @Column private int screenNumber; @Column private int capacity; -// @JsonDeserialize(using = LocalDateTimeDeserializer.class) -// @JsonSerialize(using = LocalDateTimeSerializer.class) @JsonFormat(shape=JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss[+SS][:SS]") @Column private LocalDateTime startsAt; + @Column private LocalDateTime createdAt; @Column private LocalDateTime updatedAt; @@ -139,6 +140,7 @@ public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } + @JsonIgnore public int getMovieId() { return this.movie.getId(); } diff --git a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java index e3ebabc6..99dde24f 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java @@ -1,5 +1,6 @@ package com.booleanuk.api.cinema.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import java.time.LocalDateTime; @@ -12,9 +13,11 @@ public class Ticket { private int id; @ManyToOne + @JsonIgnore private Customer customer; @ManyToOne + @JsonIgnore private Screening screening; @Column int numSeats; @@ -59,6 +62,7 @@ public void setId(int id) { this.id = id; } + @JsonIgnore public Customer getCustomer() { return customer; } @@ -67,6 +71,7 @@ public void setCustomer(Customer customer) { this.customer = customer; } + @JsonIgnore public Screening getScreening() { return screening; } @@ -99,10 +104,12 @@ public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } + @JsonIgnore public int getCustomerId() { return this.customer.getId(); } + @JsonIgnore public int getScreeningId() { return this.screening.getId(); } 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..05bf381a --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/ErrorResponse.java @@ -0,0 +1,21 @@ +package com.booleanuk.api.cinema.responses; + +import java.util.HashMap; +import java.util.Map; + +public class ErrorResponse extends Response> { + public ErrorResponse(String message) { + this.status = "error"; + Map reply = new HashMap<>(); + reply.put("message", message); + this.data = reply; + } + + 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/Response.java b/src/main/java/com/booleanuk/api/cinema/responses/Response.java new file mode 100644 index 00000000..a41594af --- /dev/null +++ b/src/main/java/com/booleanuk/api/cinema/responses/Response.java @@ -0,0 +1,39 @@ +package com.booleanuk.api.cinema.responses; + +public class Response { + protected String status; + protected T data; + + public Response(String status, T data) { + this.status = status; + this.data = data; + } + + public Response(T data) { + this("success", data); + } + + public Response() { + } + + public void set(T data) { + this.status = "success"; + this.data = data; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} From b25956c2f56f218cbf6bc920d90de08c285472bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 16:13:46 +0100 Subject: [PATCH 15/18] Cascade on delete --- src/main/java/com/booleanuk/api/cinema/model/Screening.java | 3 +++ src/main/java/com/booleanuk/api/cinema/model/Ticket.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/com/booleanuk/api/cinema/model/Screening.java b/src/main/java/com/booleanuk/api/cinema/model/Screening.java index 0e6f5825..2ea0963c 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Screening.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Screening.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import java.time.LocalDateTime; @@ -14,6 +16,7 @@ public class Screening { private int id; @ManyToOne + @OnDelete(action = OnDeleteAction.CASCADE) @JsonIgnore private Movie movie; diff --git a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java index 99dde24f..c8b32799 100644 --- a/src/main/java/com/booleanuk/api/cinema/model/Ticket.java +++ b/src/main/java/com/booleanuk/api/cinema/model/Ticket.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import java.time.LocalDateTime; @@ -18,6 +20,7 @@ public class Ticket { @ManyToOne @JsonIgnore + @OnDelete(action = OnDeleteAction.CASCADE) private Screening screening; @Column int numSeats; From b072003ee6bd13d377d7ef96e50061fd018702ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Tue, 28 Jan 2025 16:51:21 +0100 Subject: [PATCH 16/18] Add option to supply screenings array when creating movies --- .../api/cinema/controller/MovieController.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index 2ddf9b5d..556cde95 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; +import java.util.List; @RestController @RequestMapping("/movies") @@ -23,12 +24,21 @@ public MovieController(MovieRepository movieRepository, ScreeningRepository scre this.screeningRepository = screeningRepository; } + private record MovieWithScreenings(String title, String rating, String description, int runtimeMins, List screenings) {}; + @PostMapping - public ResponseEntity> createMovie(@RequestBody Movie movie) { + public ResponseEntity> createMovie(@RequestBody MovieWithScreenings movieWithScreenings) { + Movie movie = new Movie(movieWithScreenings.title, movieWithScreenings.rating, movieWithScreenings.description, movieWithScreenings.runtimeMins); Movie createdMovie = movieRepository.save(movie); if (createdMovie == null) { return new ResponseEntity<>(new ErrorResponse("bad request"), HttpStatus.BAD_REQUEST); } + if (movieWithScreenings.screenings != null) { + for (Screening s : movieWithScreenings.screenings) { + s.setMovie(createdMovie); + screeningRepository.save(s); + } + } return new ResponseEntity<>(new Response<>("success", createdMovie), HttpStatus.CREATED); } From 84c3329ffdb730e53137dcdc29a0a2d5982ff990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Wed, 29 Jan 2025 08:45:06 +0100 Subject: [PATCH 17/18] Fix ignoring fields that are not provided in update --- .../api/cinema/controller/CustomerController.java | 9 ++++++--- .../api/cinema/controller/MovieController.java | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 3c34596a..6c6db132 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -65,9 +65,12 @@ public ResponseEntity> update(@PathVariable int id, @RequestBody Cus if (customerToUpdate == null) { return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); } - customerToUpdate.setName(customer.getName()); - customerToUpdate.setEmail(customer.getEmail()); - customerToUpdate.setPhone(customer.getPhone()); + if (customer.getName() != null) + customerToUpdate.setName(customer.getName()); + if (customer.getEmail() != null) + customerToUpdate.setEmail(customer.getEmail()); + if (customer.getPhone() != null) + customerToUpdate.setPhone(customer.getPhone()); customerToUpdate.setUpdatedAt(LocalDateTime.now()); // todo error 400 return new ResponseEntity<>(new Response<>(customerRepository.save(customerToUpdate)), HttpStatus.CREATED); diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index 556cde95..0dc544bb 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -91,10 +91,14 @@ public ResponseEntity> updateMovie(@PathVariable int id, @RequestBod return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); } - movieToUpdate.setTitle(movie.getTitle()); - movieToUpdate.setRating(movie.getRating()); - movieToUpdate.setDescription(movie.getDescription()); - movieToUpdate.setRuntimeMins(movie.getRuntimeMins()); + if (movie.getTitle() != null) + movieToUpdate.setTitle(movie.getTitle()); + if (movie.getRating() != null) + movieToUpdate.setRating(movie.getRating()); + if (movie.getDescription() != null) + movieToUpdate.setDescription(movie.getDescription()); + if (movie.getRuntimeMins() > 0) + movieToUpdate.setRuntimeMins(movie.getRuntimeMins()); movieToUpdate.setUpdatedAt(LocalDateTime.now()); if (movieRepository.save(movieToUpdate) == null) { From b83cc427daa02fc5027a84484d68ece947c32f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20S=C3=B6nnergaard?= Date: Wed, 29 Jan 2025 08:45:06 +0100 Subject: [PATCH 18/18] Fix ignoring fields that are not provided in update --- .../api/cinema/controller/CustomerController.java | 11 +++++++---- .../api/cinema/controller/MovieController.java | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java index 3c34596a..1360c353 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/CustomerController.java @@ -65,9 +65,12 @@ public ResponseEntity> update(@PathVariable int id, @RequestBody Cus if (customerToUpdate == null) { return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); } - customerToUpdate.setName(customer.getName()); - customerToUpdate.setEmail(customer.getEmail()); - customerToUpdate.setPhone(customer.getPhone()); + if (customer.getName() != null) + customerToUpdate.setName(customer.getName()); + if (customer.getEmail() != null) + customerToUpdate.setEmail(customer.getEmail()); + if (customer.getPhone() != null) + customerToUpdate.setPhone(customer.getPhone()); customerToUpdate.setUpdatedAt(LocalDateTime.now()); // todo error 400 return new ResponseEntity<>(new Response<>(customerRepository.save(customerToUpdate)), HttpStatus.CREATED); @@ -77,7 +80,7 @@ public ResponseEntity> update(@PathVariable int id, @RequestBody Cus public ResponseEntity> deleteCustomer(@PathVariable int id) { Customer customer = customerRepository.findById(id).orElse(null); if (customer == null) { - return new ResponseEntity(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); + return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); } customerRepository.deleteById(id); diff --git a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java index 556cde95..0dc544bb 100644 --- a/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java +++ b/src/main/java/com/booleanuk/api/cinema/controller/MovieController.java @@ -91,10 +91,14 @@ public ResponseEntity> updateMovie(@PathVariable int id, @RequestBod return new ResponseEntity<>(new ErrorResponse("not found"), HttpStatus.NOT_FOUND); } - movieToUpdate.setTitle(movie.getTitle()); - movieToUpdate.setRating(movie.getRating()); - movieToUpdate.setDescription(movie.getDescription()); - movieToUpdate.setRuntimeMins(movie.getRuntimeMins()); + if (movie.getTitle() != null) + movieToUpdate.setTitle(movie.getTitle()); + if (movie.getRating() != null) + movieToUpdate.setRating(movie.getRating()); + if (movie.getDescription() != null) + movieToUpdate.setDescription(movie.getDescription()); + if (movie.getRuntimeMins() > 0) + movieToUpdate.setRuntimeMins(movie.getRuntimeMins()); movieToUpdate.setUpdatedAt(LocalDateTime.now()); if (movieRepository.save(movieToUpdate) == null) {