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
49 changes: 35 additions & 14 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,31 +1,52 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.1'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
id 'org.springframework.boot' version '3.4.2'
id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.booleanuk'
version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'

compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'

implementation 'jakarta.validation:jakarta.validation-api:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-validation'

}

tasks.named('bootBuildImage') {
builder = 'paketobuildpacks/builder-jammy-base:latest'
}

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

import com.booleanuk.api.cinema.models.ERole;
import com.booleanuk.api.cinema.models.Role;
import com.booleanuk.api.cinema.models.User;
import com.booleanuk.api.cinema.payload.request.LoginRequest;
import com.booleanuk.api.cinema.payload.request.SignupRequest;
import com.booleanuk.api.cinema.payload.response.JwtResponse;
import com.booleanuk.api.cinema.payload.response.MessageResponse;
import com.booleanuk.api.cinema.repository.RoleRepository;
import com.booleanuk.api.cinema.repository.UserRepository;
import com.booleanuk.api.cinema.security.jwt.JwtUtils;
import com.booleanuk.api.cinema.security.services.UserDetailsImpl;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.time.OffsetDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("auth")
public class AuthController {
@Autowired
AuthenticationManager authenticationManager;

@Autowired
UserRepository userRepository;

@Autowired
RoleRepository roleRepository;

@Autowired
PasswordEncoder encoder;

@Autowired
JwtUtils jwtUtils;

@PostMapping("/signin")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
// If using a salt for password use it here
Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);

UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream().map((item) -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity
.ok(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail(), roles));
}

@PostMapping("/signup")
public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signupRequest) {
if (userRepository.existsByUsername(signupRequest.getUsername())) {
return ResponseEntity.badRequest().body(new MessageResponse("Error: Username is already taken"));
}
if (userRepository.existsByEmail(signupRequest.getEmail())) {
return ResponseEntity.badRequest().body(new MessageResponse("Error: Email is already in use!"));
}
// Create a new user add salt here if using one
User user = new User(signupRequest.getUsername(), signupRequest.getEmail(), encoder.encode(signupRequest.getPassword()), signupRequest.getPhone());
user.setCreated(OffsetDateTime.now());
user.setUpdatedAt(OffsetDateTime.now());

Set<String> strRoles = signupRequest.getRole();
Set<Role> roles = new HashSet<>();

if (strRoles == null) {
Role userRole = roleRepository.findByName(ERole.ROLE_CUSTOMER).orElseThrow(() -> new RuntimeException("Error: Role is not found"));
roles.add(userRole);
} else {
strRoles.forEach((role) -> {
switch (role) {
case "admin":
Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN).orElseThrow(() -> new RuntimeException("Error: Role is not found"));
roles.add(adminRole);
break;
default:
Role userRole = roleRepository.findByName(ERole.ROLE_CUSTOMER).orElseThrow(() -> new RuntimeException("Error: Role is not found"));
roles.add(userRole);
break;
}
});
}
user.setRoles(roles);
userRepository.save(user);
return ResponseEntity.ok((new MessageResponse("User registered successfully")));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
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.payload.request.CreateMovieRequest;
import com.booleanuk.api.cinema.payload.response.ErrorResponse;
import com.booleanuk.api.cinema.payload.response.MovieListResponse;
import com.booleanuk.api.cinema.payload.response.MovieResponse;
import com.booleanuk.api.cinema.payload.response.Response;
import com.booleanuk.api.cinema.repository.MovieRepository;
import com.booleanuk.api.cinema.repository.ScreeningRepository;
import com.booleanuk.api.cinema.repository.TicketRepository;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.time.OffsetDateTime;
import java.util.List;

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

@Autowired
ScreeningRepository screeningRepo;

@Autowired
TicketRepository ticketRepo;

@GetMapping
public ResponseEntity<MovieListResponse> getAll(){
MovieListResponse movieList = new MovieListResponse();
movieList.set(this.repo.findAll());
return ResponseEntity.ok(movieList);
}

@PostMapping
public ResponseEntity<Response<?>> addOne(@Valid @RequestBody CreateMovieRequest req){

Movie movie = new Movie(req.getTitle(), req.getRating(), req.getDescription(), req.getRuntimeMins());
movie.setCreated(OffsetDateTime.now());
movie.setUpdatedAt(OffsetDateTime.now());

Integer createdId = repo.save(movie).getId();

List<Screening> screenings = req.getScreenings();
if(screenings != null){
for(Screening screening : screenings){
screening.setMovie(movie);
screening.setCreated(OffsetDateTime.now());
screening.setUpdatedAt(OffsetDateTime.now());

this.screeningRepo.save(screening);
}
}

MovieResponse resp = new MovieResponse();
Movie newMovie = repo.findById(createdId).orElse(null);

if(newMovie == null){
ErrorResponse error = new ErrorResponse();
error.set("Not found");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

resp.set(newMovie);
return new ResponseEntity<>(resp, HttpStatus.CREATED);
}

@PutMapping("{id}")
public ResponseEntity<Response<?>> editOne(@PathVariable Integer id, @Valid @RequestBody Movie movie){
Movie toBeEdited = this.repo.findById(id).orElse(null);

if(toBeEdited == null){
ErrorResponse error = new ErrorResponse();
error.set("Not found");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

toBeEdited.setTitle(movie.getTitle());
toBeEdited.setRating(movie.getRating());
toBeEdited.setDescription(movie.getDescription());
toBeEdited.setRuntimeMins(movie.getRuntimeMins());

toBeEdited.setUpdatedAt(OffsetDateTime.now());

MovieResponse resp = new MovieResponse();
resp.set(this.repo.save(toBeEdited));
return new ResponseEntity<>(resp, HttpStatus.CREATED);
}

@DeleteMapping("{id}")
public ResponseEntity<Response<?>> deleteOne(@PathVariable Integer id){
Movie toBeDeleted = this.repo.findById(id).orElse(null);

if(toBeDeleted == null){
ErrorResponse error = new ErrorResponse();
error.set("Not found");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

for(Screening curr : toBeDeleted.getScreenings()){
this.ticketRepo.deleteAll(curr.getTickets());
this.screeningRepo.delete(curr);
}

this.repo.delete(toBeDeleted);
MovieResponse resp = new MovieResponse();
resp.set(toBeDeleted);
return ResponseEntity.ok(resp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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.payload.response.ErrorResponse;
import com.booleanuk.api.cinema.payload.response.Response;
import com.booleanuk.api.cinema.payload.response.ScreeningListResponse;
import com.booleanuk.api.cinema.payload.response.ScreeningResponse;
import com.booleanuk.api.cinema.repository.MovieRepository;
import com.booleanuk.api.cinema.repository.ScreeningRepository;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.OffsetDateTime;
import java.util.List;

@RestController
@RequestMapping("movies/{id}/screenings")
public class ScreaningController {
@Autowired
ScreeningRepository repo;
@Autowired
MovieRepository movieRepo;

@PostMapping
public ResponseEntity<Response<?>> addOne(@PathVariable Integer id, @Valid @RequestBody Screening screening){
Movie movie = this.movieRepo.findById(id).orElse(null);

if(movie == null){
ErrorResponse error = new ErrorResponse();
error.set("Not found");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

screening.setMovie(movie);
screening.setCreated(OffsetDateTime.now());
screening.setUpdatedAt(OffsetDateTime.now());
ScreeningResponse resp = new ScreeningResponse();
resp.set(this.repo.save(screening));

return new ResponseEntity<>(resp, HttpStatus.CREATED);
}

@GetMapping
public ResponseEntity<Response<?>> getAll(@PathVariable Integer id){
ScreeningListResponse resp = new ScreeningListResponse();
Movie movie = this.movieRepo.findById(id).orElse(null);

if(movie == null){
ErrorResponse error = new ErrorResponse();
error.set("Not found");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
resp.set(movie.getScreenings());
return ResponseEntity.ok(resp);
}
}
Loading