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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ out/

### VS Code ###
.vscode/

application.yml
49 changes: 34 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
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.5.4'
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.7'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.7'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.7'

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.1'
}

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

tasks.named('test') {
useJUnitPlatform()
}
useJUnitPlatform()
}
Empty file.
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);
}
}
102 changes: 102 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,102 @@
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.repositories.RoleRepository;
import com.booleanuk.api.cinema.repositories.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.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()));
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;
case "ticketseller":
Role modRole = roleRepository.findByName(ERole.ROLE_TICKETSELLER).orElseThrow(() -> new RuntimeException("Error: Role is not found"));
roles.add(modRole);
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,89 @@
package com.booleanuk.api.cinema.controllers;

import com.booleanuk.api.cinema.models.Customer;
import com.booleanuk.api.cinema.payload.response.CustomerListResponse;
import com.booleanuk.api.cinema.payload.response.CustomerResponse;
import com.booleanuk.api.cinema.payload.response.ErrorResponse;
import com.booleanuk.api.cinema.payload.response.Response;
import com.booleanuk.api.cinema.repositories.CustomerRepository;
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;

@RestController
@RequestMapping("customers")
public class CustomerController {

@Autowired
private CustomerRepository customerRepository;

@GetMapping
public ResponseEntity<CustomerListResponse> getAllCustomers() {
CustomerListResponse customerListResponse = new CustomerListResponse();
customerListResponse.set(this.customerRepository.findAll());
return ResponseEntity.ok(customerListResponse);
}

@PostMapping
public ResponseEntity<Response<?>> createCustomer(@RequestBody Customer customer) {
CustomerResponse customerResponse = new CustomerResponse();
try {
customerResponse.set(this.customerRepository.save(customer));
} catch (Exception e) {
ErrorResponse error = new ErrorResponse();
error.set("Bad request");
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(customerResponse, HttpStatus.CREATED);
}

@PutMapping("/{id}")
public ResponseEntity<Response<?>> updateCustomer (@PathVariable int id, @RequestBody Customer customer) {
Customer customerToUpdate = this.customerRepository.findById(id).orElse(null);
if (customerToUpdate == null) {
ErrorResponse error = new ErrorResponse();
error.set("No customer with that ID found");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

if (customer.getName() == null && customer.getEmail() == null && customer.getPhone() == null) {
ErrorResponse error = new ErrorResponse();
error.set("Could not update the customer, please check all fields are correct");
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}

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(OffsetDateTime.now());

CustomerResponse customerResponse = new CustomerResponse();
customerResponse.set(this.customerRepository.save(customerToUpdate));
return new ResponseEntity<>(customerResponse, HttpStatus.CREATED);
}


@DeleteMapping("/{id}")
public ResponseEntity<Response<?>> deleteCustomer(@PathVariable int id) {
Customer customerToDelete = this.customerRepository.findById(id).orElse(null);
if (customerToDelete == null) {
ErrorResponse error = new ErrorResponse();
error.set("No customer with that ID found to delete");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

this.customerRepository.delete(customerToDelete);
CustomerResponse customerResponse = new CustomerResponse();
customerResponse.set(customerToDelete);
return new ResponseEntity<>(customerResponse, HttpStatus.CREATED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.booleanuk.api.cinema.controllers;

import com.booleanuk.api.cinema.models.Movie;
import com.booleanuk.api.cinema.payload.response.*;
import com.booleanuk.api.cinema.repositories.MovieRepository;
import com.booleanuk.api.cinema.repositories.ScreeningRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.time.OffsetDateTime;

@RestController
@RequestMapping("movies")
public class MovieController {

@Autowired
private MovieRepository movieRepository;

@GetMapping
public ResponseEntity<MovieListResponse> getAllMovies() {
MovieListResponse movieListResponse = new MovieListResponse();
movieListResponse.set(this.movieRepository.findAll());
return ResponseEntity.ok(movieListResponse);
}

@PostMapping
public ResponseEntity<Response<?>> createMovie(@RequestBody Movie movie) {
MovieResponse movieResponse = new MovieResponse();
try {
movieResponse.set(this.movieRepository.save(movie));
} catch (Exception e) {
ErrorResponse error = new ErrorResponse();
error.set("Bad request");
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(movieResponse, HttpStatus.CREATED);
}


@PutMapping("/{id}")
public ResponseEntity<Response<?>> updateMovie (@PathVariable int id, @RequestBody Movie movie) {
Movie movieToUpdate = this.movieRepository.findById(id).orElse(null);
if (movieToUpdate == null) {
ErrorResponse error = new ErrorResponse();
error.set("No movie with that ID found");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

if (movie.getTitle() == null && movie.getRating() == null && movie.getDescription() == null) {
ErrorResponse error = new ErrorResponse();
error.set("Could not update the movie, please check all fields are correct");
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}

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(OffsetDateTime.now());

MovieResponse movieResponse = new MovieResponse();
movieResponse.set(this.movieRepository.save(movieToUpdate));
return new ResponseEntity<>(movieResponse, HttpStatus.CREATED);
}

@DeleteMapping("/{id}")
public ResponseEntity<Response<?>> deleteMovie(@PathVariable int id) {
Movie movieToDelete = this.movieRepository.findById(id).orElse(null);
if (movieToDelete == null) {
ErrorResponse error = new ErrorResponse();
error.set("No movie with that ID found to delete");
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

this.movieRepository.delete(movieToDelete);
MovieResponse movieResponse = new MovieResponse();
movieResponse.set(movieToDelete);
return new ResponseEntity<>(movieResponse, HttpStatus.CREATED);
}

}
Loading