Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,30 +1,66 @@
package com.provedcode.aws.controller;

import com.amazonaws.HttpMethod;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.provedcode.aws.service.FileService;
import com.provedcode.config.AWSProperties;
import com.provedcode.util.annotations.doc.controller.aws.GetAllAWSBucketFilesDevApiDoc;
import com.provedcode.util.annotations.doc.controller.aws.GetFileInfoDevApiDoc;
import com.provedcode.util.annotations.doc.controller.aws.PostSetNewUserImageApiDoc;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.net.URL;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@RestController
@AllArgsConstructor
@RequestMapping("/api/v3/talents")
public class AWSS3BucketController {
FileService fileService;
AWSProperties awsProperties;
AmazonS3 amazonS3;

@PostSetNewUserImageApiDoc
@PreAuthorize("hasRole('TALENT')")
@PostMapping("/image/upload")
public void setNewUserImage(@RequestParam("file") MultipartFile file,
Authentication authentication) {
Authentication authentication) {
fileService.setNewUserImage(file, authentication);
}

@GetFileInfoDevApiDoc
@PreAuthorize("hasRole('TALENT')")
@GetMapping("/files")
List<String> getAllFiles() {
return fileService.listAllFiles();
}

@GetAllAWSBucketFilesDevApiDoc
@PreAuthorize("hasRole('TALENT')")
@PostMapping("/aws/test-of-filetype")
String testTypeOfFile(@RequestParam("file") MultipartFile file,
Authentication authentication) {
return Arrays.stream(file.getContentType().split("/")).toList().get(1) + " " + file.getOriginalFilename() +
" " + file.getName() + " " + file.getResource();
}

@GetMapping("/aws/test")
URL getURL() {
GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(awsProperties.bucket(), "MykhailoOrdyntsev@gmail.com/image.jpeg")
.withMethod(HttpMethod.GET);
Instant expiration = Instant.now().plusMillis(1000L * 60 * 60 * 24 * 7);

urlRequest.setExpiration(Date.from(expiration));
URL url = amazonS3.generatePresignedUrl(urlRequest);
return url;
}

}
3 changes: 3 additions & 0 deletions src/main/java/com/provedcode/aws/service/FileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
public interface FileService {

String saveFile(MultipartFile file);

byte[] downloadFile(String filename);

String deleteFile(String filename);

List<String> listAllFiles();

void setNewUserImage(MultipartFile file, Authentication authentication);
Expand Down
35 changes: 23 additions & 12 deletions src/main/java/com/provedcode/aws/service/S3Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,34 @@
import com.provedcode.talent.repo.TalentRepository;
import com.provedcode.user.model.entity.UserInfo;
import com.provedcode.user.repo.UserInfoRepository;
import com.provedcode.util.PhotoService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import static org.apache.http.entity.ContentType.*;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.NOT_IMPLEMENTED;
import static org.springframework.http.HttpStatus.*;

@Service
@AllArgsConstructor
@Slf4j
@Transactional
public class S3Service implements FileService {
AWSProperties awsProperties;
AmazonS3 s3;
UserInfoRepository userInfoRepository;
TalentRepository talentRepository;
PhotoService photoService;

@Override
public String saveFile(MultipartFile file) {
Expand Down Expand Up @@ -71,29 +75,36 @@ public List<String> listAllFiles() {
@Override
public void setNewUserImage(MultipartFile file, Authentication authentication) {
if (file.isEmpty()) {
throw new ResponseStatusException(NOT_IMPLEMENTED, "file must be not empty, actual file-size: %s".formatted(file.getSize()));
throw new ResponseStatusException(BAD_REQUEST, "file must be not empty, actual file-size: %s".formatted(file.getSize()));
}
if (!List.of(IMAGE_JPEG.getMimeType(), IMAGE_PNG.getMimeType(), IMAGE_GIF.getMimeType()).contains(file.getContentType())) {
throw new ResponseStatusException(NOT_IMPLEMENTED, "not supported type: %s".formatted(file.getContentType()));
if (photoService.isFileImage(file)) {
throw new ResponseStatusException(BAD_REQUEST, "not supported type: %s".formatted(file.getContentType()));
}
UserInfo user = userInfoRepository.findByLogin(authentication.getName())
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "user with login = {%s} not found".formatted(authentication.getName())));

String fileName = file.getOriginalFilename();

String userLogin = authentication.getName();
String fullPath = "%s/%s".formatted(userLogin, fileName);
try {
File f = convertMultiPartToFile(file);
String fileType = file.getContentType().split("/")[1];
String userLogin = authentication.getName();

String fullPath = "%s/%s".formatted(userLogin, "image.%s".formatted(fileType));
File f = photoService.degradePhoto(convertMultiPartToFile(file));

if (user.getTalent().getImageName() != null)
s3.deleteObject(awsProperties.bucket(), user.getTalent().getImageName());

s3.putObject(awsProperties.bucket(), fullPath, f);

log.info("image = {}", s3.getUrl(awsProperties.bucket(), fullPath).toString());

user.getTalent().setImage(s3.getUrl(awsProperties.bucket(), fullPath).toString());
user.getTalent().setImageName(fullPath);

talentRepository.save(user.getTalent());
} catch (RuntimeException | IOException e) {
throw new ResponseStatusException(NOT_IMPLEMENTED);
} catch (Exception e) {
throw new ResponseStatusException(SERVICE_UNAVAILABLE, "problems with connection to aws s3");
}

}

private File convertMultiPartToFile(MultipartFile file)
Expand Down
58 changes: 29 additions & 29 deletions src/main/java/com/provedcode/config/InitConfig.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
package com.provedcode.config;

import com.provedcode.user.mapper.UserInfoMapper;
import com.provedcode.user.repo.UserInfoRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@AllArgsConstructor
public class InitConfig implements CommandLineRunner {
UserInfoRepository userInfoRepository;
PasswordEncoder passwordEncoder;
UserInfoMapper userInfoMapper;

@Override
public void run(String... args) throws Exception {
// TODO: Method to change passwords for already created users from data1.sql
userInfoRepository.saveAll(
userInfoRepository.findAll().stream()
.map(i -> {
i.setPassword(passwordEncoder.encode(i.getPassword()));
return i;
}).toList());
}
}
//package com.provedcode.config;
//
//import com.provedcode.user.mapper.UserInfoMapper;
//import com.provedcode.user.repo.UserInfoRepository;
//import lombok.AllArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.boot.CommandLineRunner;
//import org.springframework.security.crypto.password.PasswordEncoder;
//import org.springframework.stereotype.Component;
//
//@Slf4j
//@Component
//@AllArgsConstructor
//public class InitConfig implements CommandLineRunner {
// UserInfoRepository userInfoRepository;
// PasswordEncoder passwordEncoder;
// UserInfoMapper userInfoMapper;
//
// @Override
// public void run(String... args) throws Exception {
// // TODO: Method to change passwords for already created users from data1.sql
// userInfoRepository.saveAll(
// userInfoRepository.findAll().stream()
// .map(i -> {
// i.setPassword(passwordEncoder.encode(i.getPassword()));
// return i;
// }).toList());
// }
//}
17 changes: 17 additions & 0 deletions src/main/java/com/provedcode/handlers/AwsS3ExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.provedcode.handlers;

import com.provedcode.handlers.dto.ErrorDTO;
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

@ControllerAdvice
public class AwsS3ExceptionHandler {
@ExceptionHandler(FileSizeLimitExceededException.class)
public ResponseEntity<?> fileSizeLimitExceededExceptionHandler(FileSizeLimitExceededException e) {
return ResponseEntity.status(BAD_REQUEST).body(new ErrorDTO("file size is too large"));
}
}
106 changes: 54 additions & 52 deletions src/main/java/com/provedcode/handlers/TalentExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
package com.provedcode.handlers;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.server.ResponseStatusException;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@ControllerAdvice
public class TalentExceptionHandler {
@ExceptionHandler(ResponseStatusException.class)
private ResponseEntity<?> responseStatusExceptionHandler(ResponseStatusException exception) {
return ResponseEntity.status(exception.getStatusCode()).body(exception.getBody());
public static boolean ignoreSQLException(String sqlState) {

if (sqlState == null) {
System.out.println("The SQL state is not defined!");
return false;
}

// X0Y32: Jar file already exists in schema
if (sqlState.equalsIgnoreCase("X0Y32"))
return true;

// 42Y55: Table already exists in schema
if (sqlState.equalsIgnoreCase("42Y55"))
return true;

return false;
}

@ExceptionHandler({SQLException.class})
Expand All @@ -29,10 +39,10 @@ public void printSQLException(SQLException ex) {

e.printStackTrace(System.err);
System.err.println("SQLState: " +
((SQLException) e).getSQLState());
((SQLException) e).getSQLState());

System.err.println("Error Code: " +
((SQLException) e).getErrorCode());
((SQLException) e).getErrorCode());

System.err.println("Message: " + e.getMessage());

Expand All @@ -46,59 +56,51 @@ public void printSQLException(SQLException ex) {
}
}

public static boolean ignoreSQLException(String sqlState) {

if (sqlState == null) {
System.out.println("The SQL state is not defined!");
return false;
}

// X0Y32: Jar file already exists in schema
if (sqlState.equalsIgnoreCase("X0Y32"))
return true;

// 42Y55: Table already exists in schema
if (sqlState.equalsIgnoreCase("42Y55"))
return true;

return false;
@ExceptionHandler(ResponseStatusException.class)
private ResponseEntity<?> responseStatusExceptionHandler(ResponseStatusException exception) {
return ResponseEntity.status(exception.getStatusCode()).body(exception.getBody());
}

@ExceptionHandler({ Exception.class })
public ResponseEntity<Object> handleAll(Exception ex, WebRequest request) {
ApiError apiError = new ApiError(
HttpStatus.INTERNAL_SERVER_ERROR, ex.getLocalizedMessage(), "error occurred");
return new ResponseEntity<Object>(
apiError, new HttpHeaders(), apiError.getStatus());
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
private ResponseEntity<?> responseStatusExceptionHandler(ConstraintViolationException exception) {
ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, exception.getMessage(), exception.toString());
return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
}

// @ExceptionHandler({ Exception.class })
// public ResponseEntity<?> handleAll(Exception ex, WebRequest request) {
// ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex.getLocalizedMessage(), "error occurred");
// return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
// }

//MethodArgumentNotValidException – This exception is thrown
// when an argument annotated with @Valid failed validation:
// @ResponseStatus(HttpStatus.BAD_REQUEST)
// @ExceptionHandler(MethodArgumentNotValidException.class)
// public Map<String, String> handleValidationExceptions(
// MethodArgumentNotValidException ex) {
// public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
// Map<String, String> errors = new HashMap<>();
// ex.getBindingResult().getAllErrors().forEach((error) -> {
// String fieldName = ((FieldError) error).getField();
// String errorMessage = error.getDefaultMessage();
// errors.put(fieldName, errorMessage);
// });
// ex.getBindingResult().getAllErrors().forEach(
// (error) -> {
// String fieldName = ((FieldError) error).getField();
// String errorMessage = error.getDefaultMessage();
// errors.put(fieldName, errorMessage);
// });
// return errors;
// }

@ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolation(
ConstraintViolationException ex, WebRequest request) {
List<String> errors = new ArrayList<>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(violation.getRootBeanClass().getName() + " " +
violation.getPropertyPath() + ": " + violation.getMessage());
}

ApiError apiError =
new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
return new ResponseEntity<Object>(
apiError, new HttpHeaders(), apiError.getStatus());
}
// @ExceptionHandler({ ConstraintViolationException.class })
// public ResponseEntity<Object> handleConstraintViolation(
// ConstraintViolationException ex, WebRequest request) {
// List<String> errors = new ArrayList<>();
// for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
// errors.add(violation.getRootBeanClass().getName() + " " +
// violation.getPropertyPath() + ": " + violation.getMessage());
// }
//
// ApiError apiError =
// new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
// return new ResponseEntity<Object>(
// apiError, new HttpHeaders(), apiError.getStatus());
// }
}
Loading