-
Notifications
You must be signed in to change notification settings - Fork 0
Merge all to master #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
5ce2926
9de1ac6
e8a260b
5902980
6883415
582402e
cadc4a1
6b61c31
0720dd9
83f7ab2
7536fd7
595bae1
7d57e4d
d575ebf
d8d8083
c5eaef3
0c5b331
49c36a8
af7e011
d89cb63
1811959
4339486
a584589
ab5b7f0
1596c81
29fbdf3
d42503b
9a2f5a8
b921619
cb5f3c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # TicketBookingApp | ||
| Seat reservation system for a multiplex. | ||
|
|
||
| ### Technologies used | ||
| * Java | ||
| * Spring Boot | ||
| * H2 Database | ||
|
|
||
| ### Assumptions | ||
| * There cannot be a single place left over in a row between two already reserved places. The seat that is on the edge can always be reserved. | ||
| * Seats can be booked at latest 15 minutes before the screening begins. | ||
| * Reservation expiration time is set to 10 minutes before the screening begins. | ||
|
|
||
| ### Build | ||
| Application is written in Java JDK version 11. The application uses Gradle wrapper to build and then run app using *java -jar*. | ||
|
|
||
| To build and run app type command: | ||
| *bash build_and_run_script.sh PORT_NUMBER* | ||
| where *PORT_NUMBER* is number of port of localhost on which app runs. When *PORT_NUMBER* is not defined, application starts on port 8080. | ||
|
|
||
| If is problem to run script, check if file *gradlew* has a execution permision. | ||
|
|
||
| ### Run use case | ||
| There are two scripts which run use case. | ||
|
|
||
| First is *run_use_cases.sh* which uses **jq** for pretty JSON formatting. | ||
|
|
||
| Second is *run_use_cases_without_jq.sh* which print JSON in normal way (as String). | ||
|
|
||
| To run use case type command: | ||
| *bash SCRIPT_NAME PORT_NUMBER* | ||
| where *PORT_NUMBER* is number of port of localhost on which app runs. When *PORT_NUMBER* is not defined, application make calls on port 8080. | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| #!/usr/bin/env sh | ||
|
|
||
| passed_port=$1 | ||
| default_port=8080 | ||
| port=${passed_port:-$default_port} | ||
|
|
||
| ./gradlew build && java -jar build/libs/ticket-booking-app-0.0.1.jar --server.port=$((port)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| #!/usr/bin/env bash | ||
| generate_post_data() | ||
| { | ||
| cat <<EOF | ||
| { | ||
| "screeningID": "$screening_id", | ||
| "firstName": "$first_name", | ||
| "lastName": "$last_name", | ||
| "tickets": [ | ||
| { | ||
| "seatID": "$seat_1", | ||
| "ticketTypeID": "$type_2" | ||
| }, | ||
| { | ||
| "seatID": "$seat_2", | ||
| "ticketTypeID": "$type_3" | ||
| }, | ||
| { | ||
| "seatID": "$seat_3", | ||
| "ticketTypeID": "$type_1" | ||
| }, | ||
| { | ||
| "seatID": "$seat_4", | ||
| "ticketTypeID": "$type_1" | ||
| } | ||
| ] | ||
| } | ||
| EOF | ||
| } | ||
|
|
||
|
|
||
| passed_port=$1 | ||
| default_port=8080 | ||
| port=${passed_port:-$default_port} | ||
|
|
||
| host="localhost:$port" | ||
|
|
||
| selected_date=`date --date="next day" +%Y-%m-%d` | ||
| time_start="14:00:00" | ||
| time_end="22:00:00" | ||
|
|
||
| list_movies_endpoint="$host/screening?date=$selected_date&timeStart=$time_start&timeEnd=$time_end" | ||
|
|
||
| echo "Selected date: $selected_date" | ||
| echo "Time interval start: $time_start" | ||
| echo "Time interval end: $time_end" | ||
| echo "The endpoint: $list_movies_endpoint" | ||
|
|
||
| curl -v ${list_movies_endpoint} | jq . | ||
|
|
||
| screening_id=2 | ||
| echo "Selected screening: $screening_id" | ||
|
|
||
| curl -v "$host/screening/$screening_id" | jq . | ||
|
|
||
|
|
||
| first_name="Ola" | ||
| last_name="Kalinowska-Jaworska" | ||
| type_1=1 | ||
| type_2=2 | ||
| type_3=3 | ||
|
|
||
| seat_1=1 | ||
| seat_2=2 | ||
| seat_3=11 | ||
| seat_4=12 | ||
|
|
||
|
|
||
|
|
||
| reservation_endpoint="$host/reservation" | ||
| echo "Post reservation request body" | ||
| echo $(generate_post_data) | jq . | ||
|
|
||
| curl -v \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d "$(generate_post_data)" \ | ||
| ${reservation_endpoint} | jq . |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| #!/usr/bin/env bash | ||
| generate_post_data() | ||
| { | ||
| cat <<EOF | ||
| { | ||
| "screeningID": "$screening_id", | ||
| "firstName": "$first_name", | ||
| "lastName": "$last_name", | ||
| "tickets": [ | ||
| { | ||
| "seatID": "$seat_1", | ||
| "ticketTypeID": "$type_2" | ||
| }, | ||
| { | ||
| "seatID": "$seat_2", | ||
| "ticketTypeID": "$type_3" | ||
| }, | ||
| { | ||
| "seatID": "$seat_3", | ||
| "ticketTypeID": "$type_1" | ||
| }, | ||
| { | ||
| "seatID": "$seat_4", | ||
| "ticketTypeID": "$type_1" | ||
| } | ||
| ] | ||
| } | ||
| EOF | ||
| } | ||
|
|
||
|
|
||
| passed_port=$1 | ||
| default_port=8080 | ||
| port=${passed_port:-$default_port} | ||
|
|
||
| host="localhost:$port" | ||
|
|
||
| selected_date=`date --date="next day" +%Y-%m-%d` | ||
| time_start="14:00:00" | ||
| time_end="22:00:00" | ||
|
|
||
| list_movies_endpoint="$host/screening?date=$selected_date&timeStart=$time_start&timeEnd=$time_end" | ||
|
|
||
| echo "Selected date: $selected_date" | ||
| echo "Time interval start: $time_start" | ||
| echo "Time interval end: $time_end" | ||
| echo "The endpoint: $list_movies_endpoint" | ||
|
|
||
| curl -v ${list_movies_endpoint} | ||
|
|
||
| screening_id=2 | ||
| echo "Selected screening: $screening_id" | ||
|
|
||
| curl -v "$host/screening/$screening_id" | ||
|
|
||
|
|
||
| first_name="Ola" | ||
| last_name="Kalinowska-Jaworska" | ||
| type_1=1 | ||
| type_2=2 | ||
| type_3=3 | ||
|
|
||
| seat_1=1 | ||
| seat_2=2 | ||
| seat_3=11 | ||
| seat_4=12 | ||
|
|
||
|
|
||
|
|
||
| reservation_endpoint="$host/reservation" | ||
| echo "Post reservation request body" | ||
| echo $(generate_post_data) | ||
|
|
||
| curl -v \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d "$(generate_post_data)" \ | ||
| ${reservation_endpoint} | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package com.mkopec.ticketbookingapp.controller; | ||
|
|
||
| import com.mkopec.ticketbookingapp.domain.Reservation; | ||
| import com.mkopec.ticketbookingapp.dtos.ReservationPostDTO; | ||
| import com.mkopec.ticketbookingapp.dtos.ShortReservationDTO; | ||
| import com.mkopec.ticketbookingapp.mapper.ReservationMapper; | ||
| import com.mkopec.ticketbookingapp.service.ReservationService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/reservation") | ||
| public class ReservationController { | ||
| private final ReservationService service; | ||
| private final ReservationMapper mapper; | ||
|
|
||
| @PostMapping | ||
| public ShortReservationDTO postReservation(@RequestBody ReservationPostDTO postDTO) { | ||
| Reservation reservation = mapper.toReservation(postDTO); | ||
| return mapper.toShortReservationDTO(service.saveReservation(reservation)); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package com.mkopec.ticketbookingapp.controller; | ||
|
|
||
| import com.mkopec.ticketbookingapp.dtos.ScreeningDTO; | ||
| import com.mkopec.ticketbookingapp.dtos.ShortScreeningDTO; | ||
| import com.mkopec.ticketbookingapp.mapper.RoomSeatMapper; | ||
| import com.mkopec.ticketbookingapp.mapper.ScreeningMapper; | ||
| import com.mkopec.ticketbookingapp.service.ScreeningService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.format.annotation.DateTimeFormat; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.time.LocalTime; | ||
| import java.util.List; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/screening") | ||
| public class ScreeningController { | ||
| private final ScreeningService service; | ||
| private final ScreeningMapper mapper; | ||
|
|
||
| private final RoomSeatMapper roomSeatMapper; | ||
|
|
||
| @GetMapping | ||
| public List<ShortScreeningDTO> getScreeningsInDayAndTimeInterval( | ||
| @RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date, | ||
| @RequestParam("timeStart") @DateTimeFormat(pattern = "HH:mm:ss") LocalTime timeStart, | ||
| @RequestParam("timeEnd") @DateTimeFormat(pattern = "HH:mm:ss") LocalTime timeEnd) { | ||
|
|
||
| return mapper.toShortScreeningDTOs(service.findAllInDayAndTimeInterval(date, timeStart, timeEnd)); | ||
| } | ||
|
|
||
| @GetMapping("/{screeningID}") | ||
| public ScreeningDTO getScreeningDetails(@PathVariable Long screeningID) { | ||
| ScreeningDTO screeningDTO = mapper.toScreeningDTO(service.findByID(screeningID)); | ||
| screeningDTO.setAvailableSeats(roomSeatMapper.toRoomSeatDTOs(service.findAvailableSeats(screeningID))); | ||
| return screeningDTO; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package com.mkopec.ticketbookingapp.domain; | ||
|
|
||
| import lombok.Data; | ||
|
|
||
| import javax.persistence.Basic; | ||
| import javax.persistence.Entity; | ||
| import javax.persistence.GeneratedValue; | ||
| import javax.persistence.Id; | ||
|
|
||
| import static javax.persistence.GenerationType.IDENTITY; | ||
|
|
||
| @Entity | ||
| @Data | ||
| public class Movie { | ||
|
|
||
| @Id | ||
| @GeneratedValue(strategy = IDENTITY) | ||
| private Long id; | ||
|
|
||
| private String title; | ||
|
|
||
| private String director; | ||
|
|
||
| @Basic | ||
| private java.time.LocalTime length; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import? i po co ten
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nie wiem o który import tutaj chodzi, prawdopodobnie o import static. Słyszałem, że dobrą praktyką jest import statyczny tych stałych (zwłaszcza gdy w jednej adnotacji może ich występować więcej). A adnotacja @basic to chyba pozostałość po wcześniejszych wersjach springa, ogólnie wzorowałem się na: https://www.baeldung.com/hibernate-date-time a tam pola oznaczone są tą adnotacją. W springu 5 działa dobrze już bez tej adnotacji. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chodziło mi o to, że tą klasę
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Racja, mój błąd |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package com.mkopec.ticketbookingapp.domain; | ||
|
|
||
| import lombok.Data; | ||
|
|
||
| import javax.persistence.*; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. importy z gwiazdkami nie są preferowane - dobre IDE i tak ci je schowa, a jak chcesz zobaczyć jaka klasa jest importowana to tak nie zobaczysz :(
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nie wiedziałem o tym, ale to kwestia ustawień IDE. Teraz już będę pamiętał |
||
| import java.math.BigDecimal; | ||
| import java.time.LocalDateTime; | ||
| import java.util.List; | ||
|
|
||
| import static javax.persistence.CascadeType.PERSIST; | ||
| import static javax.persistence.FetchType.LAZY; | ||
| import static javax.persistence.GenerationType.IDENTITY; | ||
|
|
||
| @Entity | ||
| @Data | ||
| public class Reservation { | ||
|
|
||
| @Id | ||
| @GeneratedValue(strategy = IDENTITY) | ||
| private Long id; | ||
|
|
||
| @ManyToOne(fetch = LAZY) | ||
| @JoinColumn(name = "screening_id") | ||
| private Screening screening; | ||
|
|
||
| @Column(name = "first_name") | ||
| private String firstName; | ||
|
|
||
| @Column(name = "last_name") | ||
| private String lastName; | ||
|
|
||
| @Basic | ||
| private LocalDateTime expirationTime; | ||
|
|
||
| private BigDecimal payment; | ||
|
|
||
| @OneToMany(mappedBy = "reservation", fetch = LAZY, cascade = PERSIST) | ||
| private List<Ticket> tickets; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.mkopec.ticketbookingapp.domain; | ||
|
|
||
| import lombok.Data; | ||
|
|
||
| import javax.persistence.Entity; | ||
| import javax.persistence.GeneratedValue; | ||
| import javax.persistence.Id; | ||
|
|
||
| import static javax.persistence.GenerationType.IDENTITY; | ||
|
|
||
| @Entity | ||
| @Data | ||
| public class Room { | ||
|
|
||
| @Id | ||
| @GeneratedValue(strategy = IDENTITY) | ||
| private Long id; | ||
|
|
||
| private Integer number; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nie jestem fanem mapperów, ale spoko. Generalnie do service'u mogłoby przyjść DTO i mogłoby być zwrócone DTO i byłoby OK