diff --git a/build.gradle b/build.gradle index 4e63b11..c6cb590 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.security:spring-security-crypto:6.5.3' + implementation 'org.mapstruct:mapstruct:1.5.5.Final' + annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc' diff --git a/src/main/java/ru/soune/no_copy/controller/UserContentController.java b/src/main/java/ru/soune/no_copy/controller/UserContentController.java new file mode 100644 index 0000000..49eac67 --- /dev/null +++ b/src/main/java/ru/soune/no_copy/controller/UserContentController.java @@ -0,0 +1,11 @@ +package ru.soune.no_copy.controller; + +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController("api/content") +@RequestMapping("api/content") +@AllArgsConstructor +public class UserContentController { +} diff --git a/src/main/java/ru/soune/no_copy/dto/UserContentDTO.java b/src/main/java/ru/soune/no_copy/dto/UserContentDTO.java new file mode 100644 index 0000000..90df1d9 --- /dev/null +++ b/src/main/java/ru/soune/no_copy/dto/UserContentDTO.java @@ -0,0 +1,15 @@ +package ru.soune.no_copy.dto; + +import lombok.Data; +import ru.soune.no_copy.entity.FileType; + +@Data +public class UserContentDTO { + String fileName; + String originalFilename; + String fileType; + String fileExtension; + Long fileSize; + String filePath; + Integer protectionLevel; +} diff --git a/src/main/java/ru/soune/no_copy/dto/UserContentRequest.java b/src/main/java/ru/soune/no_copy/dto/UserContentRequest.java new file mode 100644 index 0000000..de64e7f --- /dev/null +++ b/src/main/java/ru/soune/no_copy/dto/UserContentRequest.java @@ -0,0 +1,9 @@ +package ru.soune.no_copy.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; + +public record UserContentRequest(@NotBlank @Email String userEmail, @NotBlank String fileName, + @NotBlank String originalFilename, @NotBlank String fileType, + @NotBlank String fileExtension, @NotBlank Long fileSize, + @NotBlank String filePath, Integer protectionLevel) {} diff --git a/src/main/java/ru/soune/no_copy/dto/UserContentUpdateRequest.java b/src/main/java/ru/soune/no_copy/dto/UserContentUpdateRequest.java new file mode 100644 index 0000000..ba8ab5f --- /dev/null +++ b/src/main/java/ru/soune/no_copy/dto/UserContentUpdateRequest.java @@ -0,0 +1,10 @@ +package ru.soune.no_copy.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; + +public record UserContentUpdateRequest(@NotBlank @Email String userEmail, @NotBlank String fileName, + @NotBlank String originalFilename, @NotBlank String fileType, + @NotBlank String fileExtension, @NotBlank Long fileSize, + @NotBlank String filePath, Integer protectionLevel, Long id) { +} diff --git a/src/main/java/ru/soune/no_copy/exception/ContentNotFoundException.java b/src/main/java/ru/soune/no_copy/exception/ContentNotFoundException.java new file mode 100644 index 0000000..af0f040 --- /dev/null +++ b/src/main/java/ru/soune/no_copy/exception/ContentNotFoundException.java @@ -0,0 +1,7 @@ +package ru.soune.no_copy.exception; + +public class ContentNotFoundException extends RuntimeException { + public ContentNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/soune/no_copy/handler/GlobalExceptionHandler.java b/src/main/java/ru/soune/no_copy/handler/GlobalExceptionHandler.java index b25623e..3e4efbe 100644 --- a/src/main/java/ru/soune/no_copy/handler/GlobalExceptionHandler.java +++ b/src/main/java/ru/soune/no_copy/handler/GlobalExceptionHandler.java @@ -8,6 +8,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import ru.soune.no_copy.exception.ContentNotFoundException; import ru.soune.no_copy.exception.NotValidationPasswordException; import ru.soune.no_copy.exception.UserAlreadyExistsException; import ru.soune.no_copy.exception.UserNotFoundException; @@ -53,6 +54,17 @@ public class GlobalExceptionHandler { )); } + @ExceptionHandler(ContentNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ResponseEntity handleUserNotFoundException(ContentNotFoundException ex) { + return ResponseEntity. + badRequest() + .body(Map.of( + "success", false, + "message" ,ex.getMessage() + )); + } + @ExceptionHandler(NotValidationPasswordException.class) @ResponseStatus(HttpStatus.FORBIDDEN) public ResponseEntity handleNotValidationPasswordException(NotValidationPasswordException ex) { diff --git a/src/main/java/ru/soune/no_copy/mapper/UserContentMapper.java b/src/main/java/ru/soune/no_copy/mapper/UserContentMapper.java new file mode 100644 index 0000000..5617cbd --- /dev/null +++ b/src/main/java/ru/soune/no_copy/mapper/UserContentMapper.java @@ -0,0 +1,18 @@ +package ru.soune.no_copy.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; +import org.mapstruct.factory.Mappers; +import ru.soune.no_copy.dto.UserContentUpdateRequest; +import ru.soune.no_copy.entity.UserContent; + +@Mapper(componentModel = "spring", + nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface UserContentMapper { + + UserContentMapper INSTANCE = Mappers.getMapper(UserContentMapper.class); + + + void updateEntityFromDto(UserContentUpdateRequest dto, @MappingTarget UserContent entity); +} diff --git a/src/main/java/ru/soune/no_copy/repository/UserContentRepository.java b/src/main/java/ru/soune/no_copy/repository/UserContentRepository.java index aad8c79..95f524b 100644 --- a/src/main/java/ru/soune/no_copy/repository/UserContentRepository.java +++ b/src/main/java/ru/soune/no_copy/repository/UserContentRepository.java @@ -10,9 +10,9 @@ import java.util.List; public interface UserContentRepository extends JpaRepository { List findByUserIdOrderByUploadDateDesc(Long userId); - List findByUserIdAndFileTypeOrderByUploadDateDesc( - Long userId, FileType type, Pageable pageable - ); + List findByUserId(Long userId); + + List findByUserIdAndFileTypeOrderByUploadDateDesc(Long userId, FileType type, Pageable pageable); long countByUserIdAndFileType(Long userId, FileType type); diff --git a/src/main/java/ru/soune/no_copy/service/UserContentService.java b/src/main/java/ru/soune/no_copy/service/UserContentService.java new file mode 100644 index 0000000..eb89f77 --- /dev/null +++ b/src/main/java/ru/soune/no_copy/service/UserContentService.java @@ -0,0 +1,72 @@ +package ru.soune.no_copy.service; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.soune.no_copy.dto.UserContentRequest; +import ru.soune.no_copy.dto.UserContentUpdateRequest; +import ru.soune.no_copy.entity.FileType; +import ru.soune.no_copy.entity.User; +import ru.soune.no_copy.entity.UserContent; +import ru.soune.no_copy.exception.ContentNotFoundException; +import ru.soune.no_copy.exception.UserNotFoundException; +import ru.soune.no_copy.mapper.UserContentMapper; +import ru.soune.no_copy.repository.UserContentRepository; +import ru.soune.no_copy.repository.UserRepository; + +import java.util.List; +import java.util.Optional; + +@Service +@AllArgsConstructor +public class UserContentService { + + private final UserContentRepository userContentRepository; + + private final UserRepository userRepository; + + private final UserContentMapper userContentMapper; + + public List findByUser(long userId) { + return userContentRepository.findByUserId(userId); + } + + @Transactional + public UserContent addUserContent(UserContentRequest userContentRequest) { + UserContent userContent = new UserContent(); + + Optional byEmail = userRepository.findByEmail(userContentRequest.userEmail()); + User user = byEmail.orElseThrow(() -> new UserNotFoundException(userContentRequest.userEmail())); + + userContent.setUser(user); + userContent.setFilename(userContentRequest.fileName()); + userContent.setFileExtension(userContentRequest.fileExtension()); + userContent.setFilePath(userContentRequest.filePath()); + userContent.setFileType(FileType.valueOf(userContentRequest.fileType())); + userContent.setOriginalFilename(userContentRequest.originalFilename()); + userContent.setProtectionLevel(userContentRequest.protectionLevel()); + userContent.setFileSize(userContentRequest.fileSize()); + + //TODO add + // @Column(name = "protection_hash", length = 64) + // private String protectionHash; + // @Column(name = "watermark_id", length = 50) + // private String watermarkId; + + return userContentRepository.save(userContent); + } + + @Transactional + public UserContent updateUserContent(UserContentUpdateRequest userContentRequest) { + UserContent entity = userContentRepository.findById(userContentRequest.id()) + .orElseThrow(() -> new ContentNotFoundException("Content not found with: " + userContentRequest.id())); + + userContentMapper.updateEntityFromDto(userContentRequest, entity); + + return userContentRepository.save(entity); + } + + public void deleteUserContent(long userContentId) { + userContentRepository.deleteById(userContentId); + } +}