Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ dependencies {
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// Add lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}

tasks.named('test') {
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/booleanuk/api/cinema/Main.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.booleanuk.api.cinema.controllers;

import com.booleanuk.api.cinema.models.Customer;
import com.booleanuk.api.cinema.repositories.CustomerRepository;
import com.booleanuk.api.cinema.responses.CustomerListResponse;
import com.booleanuk.api.cinema.responses.CustomerResponse;
import com.booleanuk.api.cinema.responses.ErrorResponse;
import com.booleanuk.api.cinema.responses.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@RestController
@RequestMapping("customers")
public class CustomerController {
@Autowired
CustomerRepository repository;

@PostMapping
public ResponseEntity<Response<?>> create(@RequestBody Customer customer) {
CustomerResponse response = new CustomerResponse();
response.set(customer);
try {
this.repository.save(customer);
} catch (Exception e) {
ErrorResponse error = new ErrorResponse();
error.set("Could not create a new customer, please check all fields are correct.");
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(response, HttpStatus.CREATED);
}

@GetMapping
public ResponseEntity<Response<?>> getAll() {
CustomerListResponse response = new CustomerListResponse();
List<Customer> customers = this.repository.findAll();
if (customers.isEmpty()) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.set("No customers found");
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
response.set(this.repository.findAll());
return ResponseEntity.ok(response);
}

@PutMapping("{id}")
public ResponseEntity<Response<?>> update(
@PathVariable int id,
@RequestBody Customer customer)
{
CustomerResponse response = new CustomerResponse();
try {
Customer originalCustomer = this.getObjectById(id);
customer.setId(id);
customer.setCreatedAt(originalCustomer.getCreatedAt());
this.repository.save(customer);

// TODO: inefficient to call getObjectById again, refactor?
// Get the updated value, added on table update
customer.setUpdatedAt(getObjectById(id).getUpdatedAt());
response.set(customer);
} catch (Exception e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.set(e.getMessage());

// TODO: Duplicate code for HttpStatus.NOT_FOUND, both in exception and again here. Refactor?
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(response, HttpStatus.CREATED);
}

@DeleteMapping("{id}")
public ResponseEntity<Response<?>> delete(@PathVariable int id) {
CustomerResponse response = new CustomerResponse();
try {
Customer customer = getObjectById(id);
this.repository.deleteById(id);
response.set(customer);
} catch (Exception e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.set(e.getMessage());

// TODO: Duplicate code for HttpStatus.NOT_FOUND, both in exception and again here. Refactor?
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
return ResponseEntity.ok(response);
}

/**
* Get object by id.
* Can be used to check for valid id (throws exception if id doesn't exist).
* @param id .
* @return Customer
*/
private Customer getObjectById(int id) {
Customer customer = this.repository
.findById(id)
.orElseThrow(
() -> new ResponseStatusException(
HttpStatus.NOT_FOUND,
"No customer with id #"+id+" found."
)
);
return customer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.booleanuk.api.cinema.controllers;

import com.booleanuk.api.cinema.models.Customer;
import com.booleanuk.api.cinema.models.Movie;
import com.booleanuk.api.cinema.models.Screening;
import com.booleanuk.api.cinema.repositories.MovieRepository;
import com.booleanuk.api.cinema.repositories.ScreeningRepository;
import com.booleanuk.api.cinema.responses.MovieResponse;
import com.booleanuk.api.cinema.responses.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@RestController
@RequestMapping("movies")
public class MovieController {
@Autowired
private MovieRepository repository;

@Autowired
private ScreeningRepository associatedScreeningRepository;

// TODO: Handle case when the payload is a screening object instead of Id's
@PostMapping
public ResponseEntity<Response<?>> create(@RequestBody Movie movie) {
Movie newMovie = this.repository.save(movie);

// Create corresponding screenings
List<Screening> screenings = movie.getScreenings();
for (Screening s : screenings) {
Screening existingScreening = this.associatedScreeningRepository.findById(s.getId()).orElse(null);
if (existingScreening == null) {
s.setMovie(newMovie);
this.associatedScreeningRepository.save(s);
} else {
existingScreening.setMovie(newMovie);
}
}
// Save to database
this.repository.save(newMovie);

// Update response
MovieResponse response = new MovieResponse();
response.set(newMovie);
return new ResponseEntity<>(response, HttpStatus.CREATED);
}

@GetMapping
public ResponseEntity<List<Movie>> getAll() {
return ResponseEntity.ok(this.repository.findAll());
}

@PutMapping("{id}")
public ResponseEntity<Movie> update(
@PathVariable int id,
@RequestBody Movie movie)
{
Movie originalMovie = getObjectById(id);
movie.setId(id);
movie.setCreatedAt(originalMovie.getCreatedAt());
movie.setScreenings(originalMovie.getScreenings());
return new ResponseEntity<>(this.repository.save(movie), HttpStatus.CREATED);
}

@DeleteMapping("{id}")
public ResponseEntity<Movie> delete(@PathVariable int id) {
Movie movie = getObjectById(id);
try {
this.repository.deleteById(id);
} catch (Exception e) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Could not delete customer. Detailed information: "+e.getMessage()
);
}
return ResponseEntity.ok(movie);
}

/**
* Get object by id.
* Can be used to check for valid id (throws exception if id doesn't exist).
* @param id .
* @return Customer
*/
private Movie getObjectById(int id) {
Movie movie = this.repository
.findById(id)
.orElseThrow(
() -> new ResponseStatusException(
HttpStatus.NOT_FOUND,
"No movie with id #"+id+" found."
)
);
return movie;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.booleanuk.api.cinema.controllers;

import com.booleanuk.api.cinema.models.Movie;
import com.booleanuk.api.cinema.models.Screening;
import com.booleanuk.api.cinema.repositories.MovieRepository;
import com.booleanuk.api.cinema.repositories.ScreeningRepository;
import com.booleanuk.api.cinema.responses.Response;
import com.booleanuk.api.cinema.responses.ScreeningResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@RestController
@RequestMapping("movies")
public class ScreeningController {
@Autowired
private ScreeningRepository repository;

@Autowired
private MovieRepository associatedMovieRepository;

@PostMapping("{id}/screenings")
public ResponseEntity<Response<?>> create(
@PathVariable int id,
@RequestBody Screening screening)
{
Screening newScreening = this.repository.save(screening);

// Get movie
Movie movie = this.associatedMovieRepository.findById(id).orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie with this id not found.")
);

// Associate the movie with this screening
newScreening.setMovie(movie);
// Update screening list for the movie
movie.getScreenings().add(newScreening);
this.associatedMovieRepository.save(movie);

// Create response object
ScreeningResponse response = new ScreeningResponse();
response.set(newScreening);
return new ResponseEntity<>(response, HttpStatus.CREATED);
}

@GetMapping("{id}/screenings")
public ResponseEntity<List<Screening>> getAll(@PathVariable int id) {
return ResponseEntity.ok(this.repository.findAllByMovieId(id));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.booleanuk.api.cinema.controllers;

import com.booleanuk.api.cinema.models.Customer;
import com.booleanuk.api.cinema.models.Screening;
import com.booleanuk.api.cinema.models.Ticket;
import com.booleanuk.api.cinema.repositories.CustomerRepository;
import com.booleanuk.api.cinema.repositories.ScreeningRepository;
import com.booleanuk.api.cinema.repositories.TicketRepository;
import com.booleanuk.api.cinema.responses.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("customers/{customerId}/screenings/{screeningId}")
public class TicketController {
@Autowired
TicketRepository repository;

@Autowired
CustomerRepository customerRepository;

@Autowired
ScreeningRepository screeningRepository;

@PostMapping
public ResponseEntity<Response<?>> create(
@PathVariable int customerId,
@PathVariable int screeningId,
@RequestBody Ticket ticket) {

Customer customer = this.customerRepository.findById(customerId).orElse(null);
Screening screening = this.screeningRepository.findById(screeningId).orElse(null);
if (customer == null || screening == null) {
// TODO: Could improve ux with better error message / more specific
ErrorResponse error = new ErrorResponse();
error.set("Invalid customer or screening id");
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}

ticket.setCustomer(customer);
ticket.setScreening(screening);

try {
this.repository.save(ticket);
} catch (Exception e) {
ErrorResponse error = new ErrorResponse();
error.set("Could not create a new ticket, please check all fields are correct.");
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
TicketResponse response = new TicketResponse();
response.set(ticket);
return new ResponseEntity<>(response, HttpStatus.CREATED);
}

@GetMapping
public ResponseEntity<Response<?>> getAll(
@PathVariable int customerId,
@PathVariable int screeningId
) {
TicketListResponse response = new TicketListResponse();
List<Ticket> tickets = this.repository.findAllByCustomerIdAndScreeningId(customerId, screeningId);
if (tickets.isEmpty()) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.set("No tickets found");
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
response.set(tickets);
return ResponseEntity.ok(response);
}
}
Loading