From 9b066a03ad9637630a619be8d6955718391ff0ac Mon Sep 17 00:00:00 2001 From: Yesitha Sathsara <60166952+yesitha@users.noreply.github.com> Date: Fri, 14 Mar 2025 12:03:51 +0530 Subject: [PATCH] added user image functionality --- .../main/java/com/itgura/util/URIPrefix.java | 1 + .../com/itgura/controller/UserController.java | 12 ++++ .../main/java/com/itgura/entity/Student.java | 5 ++ .../itgura/repository/StudentRepository.java | 10 +++ .../response/dto/UserDetailsResponse.java | 5 ++ .../response/dto/mapper/UserDetailMapper.java | 27 +++++++- .../com/itgura/service/UserDetailService.java | 6 +- .../service/impl/UserDetailsServiceImpl.java | 64 ++++++++++++++++++- 8 files changed, 123 insertions(+), 7 deletions(-) diff --git a/lib-global/src/main/java/com/itgura/util/URIPrefix.java b/lib-global/src/main/java/com/itgura/util/URIPrefix.java index 68483a0..34504cc 100644 --- a/lib-global/src/main/java/com/itgura/util/URIPrefix.java +++ b/lib-global/src/main/java/com/itgura/util/URIPrefix.java @@ -31,4 +31,5 @@ public class URIPrefix { public static final String Upload_Video_Material = "/upload-video"; public static final String GET_Pre_Signed_Url_To_Upload_Video = "/get-pre-signed-url-to-upload-video"; public static final String MARKED_VIDEO_AS_UPLOADED = "/marked-video-as-uploaded"; + public static final String UPDATE_PROFILE_PICTURE = "/update-profile-picture"; } diff --git a/resource-management/resource-management-all/src/main/java/com/itgura/controller/UserController.java b/resource-management/resource-management-all/src/main/java/com/itgura/controller/UserController.java index 11e149d..6321ada 100644 --- a/resource-management/resource-management-all/src/main/java/com/itgura/controller/UserController.java +++ b/resource-management/resource-management-all/src/main/java/com/itgura/controller/UserController.java @@ -12,6 +12,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.UUID; @RestController @@ -48,4 +51,13 @@ public AppResponse updateUser(@RequestBody @Valid UserDetai return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); } } + @PatchMapping (value=ResourceManagementURI.USER_DETAILS + URIPrefix.UPDATE_PROFILE_PICTURE, consumes = "multipart/form-data") + public AppResponse updateProfilePicture( @RequestParam(value = "userImage") MultipartFile file) { + try { + String response = userService.updateProfilePicture(file); + return AppResponse.ok(response); + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } } diff --git a/resource-management/resource-management-dao/src/main/java/com/itgura/entity/Student.java b/resource-management/resource-management-dao/src/main/java/com/itgura/entity/Student.java index 97bc011..322191f 100644 --- a/resource-management/resource-management-dao/src/main/java/com/itgura/entity/Student.java +++ b/resource-management/resource-management-dao/src/main/java/com/itgura/entity/Student.java @@ -39,6 +39,11 @@ public class Student { private String gender; @Column(name = "school") private String school; + @Lob + @Column(name = "profile_picture") + private Byte[]profilePicture; + @Column(name = "profile_picture_name") + private String profilePictureName; @ManyToOne @JoinColumn(name = "stream_id") private Stream stream; diff --git a/resource-management/resource-management-dao/src/main/java/com/itgura/repository/StudentRepository.java b/resource-management/resource-management-dao/src/main/java/com/itgura/repository/StudentRepository.java index 8d32a10..6d32ba7 100644 --- a/resource-management/resource-management-dao/src/main/java/com/itgura/repository/StudentRepository.java +++ b/resource-management/resource-management-dao/src/main/java/com/itgura/repository/StudentRepository.java @@ -3,8 +3,10 @@ import com.itgura.entity.Student; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.Optional; @@ -17,4 +19,12 @@ public interface StudentRepository extends JpaRepository { @Query("SELECT MAX(s.registration_number) FROM Student s") Integer findMaxRegistrationNumber(); + + @Modifying + @Query("UPDATE Student s SET s.profilePicture = :profilePicture WHERE s.userId = :userId") + int updateProfilePicture( UUID userId,Byte[] profilePicture); + + @Modifying + @Query("UPDATE Student s SET s.profilePictureName = :originalFilename WHERE s.userId = :userId") + void updateProfilePictureName(UUID userId, String originalFilename); } diff --git a/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/UserDetailsResponse.java b/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/UserDetailsResponse.java index 61a2641..b3b70e9 100644 --- a/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/UserDetailsResponse.java +++ b/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/UserDetailsResponse.java @@ -63,4 +63,9 @@ public class UserDetailsResponse { private String city; @JsonProperty("user_roles") private String userRoles; + + @JsonProperty("profile_picture") + private String profilePicture; + @JsonProperty("profile_picture_name") + private String profilePictureName; } diff --git a/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/mapper/UserDetailMapper.java b/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/mapper/UserDetailMapper.java index edfc21f..ecf1ec7 100644 --- a/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/mapper/UserDetailMapper.java +++ b/resource-management/resource-management-dao/src/main/java/com/itgura/response/dto/mapper/UserDetailMapper.java @@ -1,16 +1,24 @@ package com.itgura.response.dto.mapper; + + import com.itgura.entity.Material; import com.itgura.entity.Session; import com.itgura.entity.Student; + import com.itgura.response.dto.MaterialResponseDto; import com.itgura.response.dto.SessionResponseDto; import com.itgura.response.dto.UserDetailsResponse; +import org.apache.commons.lang.ArrayUtils; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; +import org.mapstruct.Named; import org.mapstruct.factory.Mappers; + +import java.util.Base64; import java.util.List; -@Mapper + +@Mapper(componentModel = "spring", imports = {Base64.class, java.util.Arrays.class}) public interface UserDetailMapper { UserDetailMapper INSTANCE = Mappers.getMapper(UserDetailMapper.class); @Mappings({ @@ -30,7 +38,20 @@ public interface UserDetailMapper { @Mapping(target = "houseNameOrNumber", source = "student.address.houseNameOrNumber"), @Mapping(target = "line1", source = "student.address.line1"), @Mapping(target = "line2", source = "student.address.line2"), - @Mapping(target = "city", source = "student.address.city") + @Mapping(target = "city", source = "student.address.city"), + @Mapping(target = "profilePicture", source = "student.profilePicture", qualifiedByName = "mapProfilePicture"), + @Mapping(target = "profilePictureName", source = "student.profilePictureName") }) UserDetailsResponse toDto(Student student); -} \ No newline at end of file + + @Named("mapProfilePicture") + default String mapProfilePicture(Byte[] profilePicture) { + if (profilePicture != null) { + byte[] primitiveBytes = ArrayUtils.toPrimitive(profilePicture); + return Base64.getEncoder().encodeToString(primitiveBytes); + } + return null; + } + + +} diff --git a/resource-management/resource-management-service/src/main/java/com/itgura/service/UserDetailService.java b/resource-management/resource-management-service/src/main/java/com/itgura/service/UserDetailService.java index e031a48..eeafdb5 100644 --- a/resource-management/resource-management-service/src/main/java/com/itgura/service/UserDetailService.java +++ b/resource-management/resource-management-service/src/main/java/com/itgura/service/UserDetailService.java @@ -1,9 +1,11 @@ package com.itgura.service; import com.itgura.exception.BadRequestRuntimeException; +import com.itgura.exception.ValueNotFoundException; import com.itgura.request.UserDetailRequest; import com.itgura.request.dto.UserResponseDto; import com.itgura.response.dto.UserDetailsResponse; +import org.springframework.web.multipart.MultipartFile; import javax.security.auth.login.CredentialNotFoundException; @@ -12,4 +14,6 @@ public interface UserDetailService { UserDetailsResponse findUser(); UserDetailsResponse registerUser(UserDetailRequest userDetailRequest); UserDetailsResponse updateUser(UserDetailRequest userDetailRequest); -} \ No newline at end of file + + String updateProfilePicture(MultipartFile file) throws BadRequestRuntimeException, ValueNotFoundException; +} diff --git a/resource-management/resource-management-service/src/main/java/com/itgura/service/impl/UserDetailsServiceImpl.java b/resource-management/resource-management-service/src/main/java/com/itgura/service/impl/UserDetailsServiceImpl.java index 4cce72d..1d1c266 100644 --- a/resource-management/resource-management-service/src/main/java/com/itgura/service/impl/UserDetailsServiceImpl.java +++ b/resource-management/resource-management-service/src/main/java/com/itgura/service/impl/UserDetailsServiceImpl.java @@ -4,6 +4,7 @@ import com.itgura.entity.Address; import com.itgura.entity.Stream; import com.itgura.entity.Student; +import com.itgura.exception.ApplicationException; import com.itgura.exception.BadRequestRuntimeException; import com.itgura.exception.ValueNotFoundException; import com.itgura.repository.AddressRepository; @@ -16,11 +17,18 @@ import com.itgura.response.dto.mapper.UserDetailMapper; import com.itgura.service.UserDetailService; import com.itgura.util.UserUtil; +import jakarta.transaction.Transactional; +import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import javax.security.auth.login.CredentialNotFoundException; +import java.io.IOException; +import java.util.Base64; +import java.util.Objects; +import java.util.Optional; import java.util.UUID; @Service @@ -45,18 +53,26 @@ public UserResponseDto getLoggedUserDetails(String token) throws BadRequestRunti } @Override + @Transactional public UserDetailsResponse findUser() { try{ UserResponseDto loggedUserDetails = getLoggedUserDetails(UserUtil.extractToken()); - System.out.println("Extract details from token :"+loggedUserDetails); + UUID userId = loggedUserDetails.getUserId(); - System.out.println("Extract details from token :"+loggedUserDetails); + Student student = studentRepository.findByUserId(userId) .orElseThrow(() -> { return new ValueNotFoundException("user not found id: " + userId); }); + UserDetailsResponse dto = UserDetailMapper.INSTANCE.toDto(student); +// if(student.getProfilePicture()!=null) { +// dto.setProfilePicture(Base64.getEncoder().encodeToString(ArrayUtils.toPrimitive(student.getProfilePicture()))); +// }else { +// dto.setProfilePicture(null); +// } + dto.setUserRoles(loggedUserDetails.getUserRoles()); return dto; @@ -226,4 +242,46 @@ public UserDetailsResponse updateUser(UserDetailRequest userDetailRequest) { } } -} + @Override + @Transactional + public String updateProfilePicture(MultipartFile file) throws BadRequestRuntimeException, ValueNotFoundException { + try { + if (file == null) { + throw new BadRequestRuntimeException("Profile picture is required"); + } + + String ext = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf('.') + 1).toLowerCase(); + if (!ext.equals("jpg") && !ext.equals("jpeg") && !ext.equals("png")) { + throw new BadRequestRuntimeException("Profile picture must be in JPG, JPEG, or PNG format"); + } + + UserResponseDto loggedUserDetails = getLoggedUserDetails(UserUtil.extractToken()); + UUID userId = loggedUserDetails.getUserId(); + + // Find the existing Student record associated with the logged-in user + + if (!studentRepository.existsById(userId)) { + new ValueNotFoundException("User not found with ID: " + userId); + } + // Convert the MultipartFile to a byte array + + studentRepository.updateProfilePicture(userId,ArrayUtils.toObject(file.getBytes())); + studentRepository.updateProfilePictureName(userId,file.getOriginalFilename()); + + return "Profile picture updated successfully"; + + } catch(ValueNotFoundException e){ + throw e; + }catch(IllegalArgumentException e){ + throw new BadRequestRuntimeException(e.getMessage()); + + } catch(BadRequestRuntimeException e){ + throw e; + } catch(Exception e){ + throw new RuntimeException("Failed to update profile picture", e); + + } + } + + + }