From 77541c2a9d7b3f7bf848162fe22778001e54f00f Mon Sep 17 00:00:00 2001 From: heyethereum Date: Sat, 20 Jul 2024 22:12:22 +0800 Subject: [PATCH] added new endpoints delete scanned history, delete all scanned histories, delete bookmarks, delete all bookmarks --- .../safeqr/app/constants/APIConstants.java | 5 ++ .../exceptions/CustomNotFoundExceptions.java | 7 -- .../exceptions/GlobalExceptionHandler.java | 8 +- .../app/exceptions/ResourceAlreadyExists.java | 7 ++ .../ResourceNotFoundExceptions.java | 7 ++ .../app/qrcode/entity/ScanBookmarkEntity.java | 18 ++++- .../app/qrcode/entity/ScanHistoryEntity.java | 14 ++++ .../repository/ScanBookmarkRepository.java | 16 +++- .../repository/ScanHistoryRepository.java | 10 +++ .../service/EmailVerificationService.java | 4 +- .../service/PhoneVerificationService.java | 4 +- .../app/qrcode/service/QRCodeTypeService.java | 6 +- .../service/SMSVerificationService.java | 4 +- .../service/TextVerificationService.java | 4 +- .../service/URLVerificationService.java | 4 +- .../service/WifiVerificationService.java | 4 +- .../app/user/controller/UserController.java | 37 ++++++++- .../com/safeqr/app/user/dto/BaseResponse.java | 11 +++ .../app/user/dto/BookmarkRequestDto.java | 10 +++ .../safeqr/app/user/service/UserService.java | 78 ++++++++++++++++++- 20 files changed, 226 insertions(+), 32 deletions(-) delete mode 100644 src/main/java/com/safeqr/app/exceptions/CustomNotFoundExceptions.java create mode 100644 src/main/java/com/safeqr/app/exceptions/ResourceAlreadyExists.java create mode 100644 src/main/java/com/safeqr/app/exceptions/ResourceNotFoundExceptions.java create mode 100644 src/main/java/com/safeqr/app/user/dto/BaseResponse.java create mode 100644 src/main/java/com/safeqr/app/user/dto/BookmarkRequestDto.java diff --git a/src/main/java/com/safeqr/app/constants/APIConstants.java b/src/main/java/com/safeqr/app/constants/APIConstants.java index 041036f..5648072 100644 --- a/src/main/java/com/safeqr/app/constants/APIConstants.java +++ b/src/main/java/com/safeqr/app/constants/APIConstants.java @@ -16,6 +16,11 @@ public class APIConstants { public static final String API_URL_USER_GET = "/user/getUser"; public static final String API_URL_USER_GET_SCANNED_HISTORIES = "/user/getScannedHistories"; + public static final String API_URL_USER_DELETE_SCANNED_HISTORIES = "/user/deleteScannedHistories"; + public static final String API_URL_USER_DELETE_ALL_SCANNED_HISTORIES = "/user/deleteAllScannedHistories"; public static final String API_URL_USER_GET_BOOKMARKS = "/user/getBookmarks"; + public static final String API_URL_USER_SET_BOOKMARK = "/user/setBookmark"; + public static final String API_URL_USER_DELETE_BOOKMARK = "/user/deleteBookmark"; + public static final String API_URL_USER_DELETE_ALL_BOOKMARK = "/user/deleteAllBookmark"; } diff --git a/src/main/java/com/safeqr/app/exceptions/CustomNotFoundExceptions.java b/src/main/java/com/safeqr/app/exceptions/CustomNotFoundExceptions.java deleted file mode 100644 index ba86412..0000000 --- a/src/main/java/com/safeqr/app/exceptions/CustomNotFoundExceptions.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.safeqr.app.exceptions; - -public class CustomNotFoundExceptions extends RuntimeException { - public CustomNotFoundExceptions(String message){ - super(message); - } -} diff --git a/src/main/java/com/safeqr/app/exceptions/GlobalExceptionHandler.java b/src/main/java/com/safeqr/app/exceptions/GlobalExceptionHandler.java index 29e8622..58ecb35 100644 --- a/src/main/java/com/safeqr/app/exceptions/GlobalExceptionHandler.java +++ b/src/main/java/com/safeqr/app/exceptions/GlobalExceptionHandler.java @@ -8,8 +8,12 @@ import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class GlobalExceptionHandler { - @ExceptionHandler(CustomNotFoundExceptions.class) - public ResponseEntity handleResourceNotFoundException(CustomNotFoundExceptions e) { + @ExceptionHandler(ResourceNotFoundExceptions.class) + public ResponseEntity handleResourceNotFoundException(ResourceNotFoundExceptions e) { return new ResponseEntity<>(new ErrorResponse(e.getMessage(), HttpStatus.NOT_FOUND.value()), HttpStatus.NOT_FOUND); } + @ExceptionHandler(ResourceAlreadyExists.class) + public ResponseEntity handleResourceAlreadyExistsException(ResourceAlreadyExists e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage(), HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); + } } diff --git a/src/main/java/com/safeqr/app/exceptions/ResourceAlreadyExists.java b/src/main/java/com/safeqr/app/exceptions/ResourceAlreadyExists.java new file mode 100644 index 0000000..fbf8601 --- /dev/null +++ b/src/main/java/com/safeqr/app/exceptions/ResourceAlreadyExists.java @@ -0,0 +1,7 @@ +package com.safeqr.app.exceptions; + +public class ResourceAlreadyExists extends RuntimeException { + public ResourceAlreadyExists(String message){ + super(message); + } +} diff --git a/src/main/java/com/safeqr/app/exceptions/ResourceNotFoundExceptions.java b/src/main/java/com/safeqr/app/exceptions/ResourceNotFoundExceptions.java new file mode 100644 index 0000000..405bac2 --- /dev/null +++ b/src/main/java/com/safeqr/app/exceptions/ResourceNotFoundExceptions.java @@ -0,0 +1,7 @@ +package com.safeqr.app.exceptions; + +public class ResourceNotFoundExceptions extends RuntimeException { + public ResourceNotFoundExceptions(String message){ + super(message); + } +} diff --git a/src/main/java/com/safeqr/app/qrcode/entity/ScanBookmarkEntity.java b/src/main/java/com/safeqr/app/qrcode/entity/ScanBookmarkEntity.java index 7c67f7f..eb62ffa 100644 --- a/src/main/java/com/safeqr/app/qrcode/entity/ScanBookmarkEntity.java +++ b/src/main/java/com/safeqr/app/qrcode/entity/ScanBookmarkEntity.java @@ -5,6 +5,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.NoArgsConstructor; +import java.time.OffsetDateTime; import java.util.UUID; @Entity @@ -25,8 +26,14 @@ public class ScanBookmarkEntity { private String userId; @Enumerated(EnumType.STRING) - @Column(name = "status", nullable = false) - private BookmarkStatus scanStatus; + @Column(name = "status") + private BookmarkStatus bookmarkStatus; + + @Column(name = "date_created", updatable = false) + private OffsetDateTime dateCreated; + + @Column(name = "date_updated") + private OffsetDateTime dateUpdated; public enum BookmarkStatus { ACTIVE, @@ -36,4 +43,11 @@ public class ScanBookmarkEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "qr_code_id", referencedColumnName = "id", insertable = false, updatable = false) private QRCodeEntity qrCodeEntity; + + @PrePersist + public void prePersist() { + OffsetDateTime now = OffsetDateTime.now(); + dateCreated = now; + dateUpdated = now; + } } \ No newline at end of file diff --git a/src/main/java/com/safeqr/app/qrcode/entity/ScanHistoryEntity.java b/src/main/java/com/safeqr/app/qrcode/entity/ScanHistoryEntity.java index d99311c..bc7088b 100644 --- a/src/main/java/com/safeqr/app/qrcode/entity/ScanHistoryEntity.java +++ b/src/main/java/com/safeqr/app/qrcode/entity/ScanHistoryEntity.java @@ -5,6 +5,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.NoArgsConstructor; +import java.time.OffsetDateTime; import java.util.UUID; @Entity @@ -28,6 +29,12 @@ public class ScanHistoryEntity { @Column(name = "status") private ScanStatus scanStatus; + @Column(name = "date_created", updatable = false) + private OffsetDateTime dateCreated; + + @Column(name = "date_updated") + private OffsetDateTime dateUpdated; + public enum ScanStatus { ACTIVE, INACTIVE @@ -35,4 +42,11 @@ public class ScanHistoryEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "qr_code_id", referencedColumnName = "id", insertable = false, updatable = false) private QRCodeEntity qrCodeEntity; + + @PrePersist + public void prePersist() { + OffsetDateTime now = OffsetDateTime.now(); + dateCreated = now; + dateUpdated = now; + } } \ No newline at end of file diff --git a/src/main/java/com/safeqr/app/qrcode/repository/ScanBookmarkRepository.java b/src/main/java/com/safeqr/app/qrcode/repository/ScanBookmarkRepository.java index 6a44bbf..24c4bc4 100644 --- a/src/main/java/com/safeqr/app/qrcode/repository/ScanBookmarkRepository.java +++ b/src/main/java/com/safeqr/app/qrcode/repository/ScanBookmarkRepository.java @@ -3,11 +3,25 @@ package com.safeqr.app.qrcode.repository; import com.safeqr.app.qrcode.entity.QRCodeEntity; import com.safeqr.app.qrcode.entity.ScanBookmarkEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import java.util.List; +import java.util.Optional; +import java.util.UUID; public interface ScanBookmarkRepository extends JpaRepository { - @Query("SELECT sb.qrCodeEntity FROM ScanBookmarkEntity sb WHERE sb.userId = :userId AND sb.scanStatus = 'ACTIVE'") + @Query("SELECT sb.qrCodeEntity FROM ScanBookmarkEntity sb WHERE sb.userId = :userId AND sb.bookmarkStatus = 'ACTIVE'") List findAllBookmarksByUserId(String userId); + + @Query("SELECT sb FROM ScanBookmarkEntity sb WHERE sb.userId = :userId AND sb.qrCodeId = :qrCodeId AND sb.bookmarkStatus = 'ACTIVE'") + Optional findByUserIdAndQrCodeId(String userId, UUID qrCodeId); + + @Modifying + @Query("UPDATE ScanBookmarkEntity sb SET sb.bookmarkStatus = com.safeqr.app.qrcode.entity.ScanBookmarkEntity$BookmarkStatus.INACTIVE, sb.dateUpdated = CURRENT_TIMESTAMP WHERE sb.userId = :userId AND sb.bookmarkStatus = com.safeqr.app.qrcode.entity.ScanBookmarkEntity$BookmarkStatus.ACTIVE AND sb.qrCodeId = :qrCodeId") + int updateBookmarkStatusToInactive(String userId, UUID qrCodeId); + + @Modifying + @Query("UPDATE ScanBookmarkEntity sb SET sb.bookmarkStatus = com.safeqr.app.qrcode.entity.ScanBookmarkEntity$BookmarkStatus.INACTIVE, sb.dateUpdated = CURRENT_TIMESTAMP WHERE sb.userId = :userId AND sb.bookmarkStatus = com.safeqr.app.qrcode.entity.ScanBookmarkEntity$BookmarkStatus.ACTIVE") + int updateBookmarkStatusToInactiveByUserId(String userId); } diff --git a/src/main/java/com/safeqr/app/qrcode/repository/ScanHistoryRepository.java b/src/main/java/com/safeqr/app/qrcode/repository/ScanHistoryRepository.java index 925408b..f382872 100644 --- a/src/main/java/com/safeqr/app/qrcode/repository/ScanHistoryRepository.java +++ b/src/main/java/com/safeqr/app/qrcode/repository/ScanHistoryRepository.java @@ -3,13 +3,23 @@ package com.safeqr.app.qrcode.repository; import com.safeqr.app.qrcode.entity.QRCodeEntity; import com.safeqr.app.qrcode.entity.ScanHistoryEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.UUID; @Repository public interface ScanHistoryRepository extends JpaRepository { @Query("SELECT sh.qrCodeEntity FROM ScanHistoryEntity sh WHERE sh.userId = :userId AND sh.scanStatus = 'ACTIVE'") List findAllQRCodesByUserId(String userId); + + @Modifying + @Query("UPDATE ScanHistoryEntity sh SET sh.scanStatus = com.safeqr.app.qrcode.entity.ScanHistoryEntity$ScanStatus.INACTIVE, sh.dateUpdated = CURRENT_TIMESTAMP WHERE sh.userId = :userId AND sh.scanStatus = com.safeqr.app.qrcode.entity.ScanHistoryEntity$ScanStatus.ACTIVE AND sh.qrCodeId = :qrCodeId") + int updateScannedHistoryToInactive(String userId, UUID qrCodeId); + + @Modifying + @Query("UPDATE ScanHistoryEntity sh SET sh.scanStatus = com.safeqr.app.qrcode.entity.ScanHistoryEntity$ScanStatus.INACTIVE, sh.dateUpdated = CURRENT_TIMESTAMP WHERE sh.userId = :userId AND sh.scanStatus = com.safeqr.app.qrcode.entity.ScanHistoryEntity$ScanStatus.ACTIVE") + int updateScannedHistoriesToInactiveByUserId(String userId); } \ No newline at end of file diff --git a/src/main/java/com/safeqr/app/qrcode/service/EmailVerificationService.java b/src/main/java/com/safeqr/app/qrcode/service/EmailVerificationService.java index 83d38c6..7341221 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/EmailVerificationService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/EmailVerificationService.java @@ -1,6 +1,6 @@ package com.safeqr.app.qrcode.service; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.entity.EmailEntity; import com.safeqr.app.qrcode.repository.EmailRepository; import org.slf4j.Logger; @@ -22,7 +22,7 @@ public class EmailVerificationService { public EmailEntity getEmailEntityByQRCodeId(UUID qrCodeId) { logger.info("qrCodeId retrieving: {}", qrCodeId); return emailRepository.findByQrCodeId(qrCodeId) - .orElseThrow(() -> new CustomNotFoundExceptions("Email not found for QR Code id: " + qrCodeId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("Email not found for QR Code id: " + qrCodeId)); } public void insertDB(EmailEntity emailEntity) { emailRepository.save(emailEntity); diff --git a/src/main/java/com/safeqr/app/qrcode/service/PhoneVerificationService.java b/src/main/java/com/safeqr/app/qrcode/service/PhoneVerificationService.java index d1c6401..50e392e 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/PhoneVerificationService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/PhoneVerificationService.java @@ -1,6 +1,6 @@ package com.safeqr.app.qrcode.service; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.entity.PhoneEntity; import com.safeqr.app.qrcode.repository.PhoneRepository; import org.slf4j.Logger; @@ -22,7 +22,7 @@ public class PhoneVerificationService { public PhoneEntity getPhoneEntityByQRCodeId(UUID qrCodeId) { logger.info("qrCodeId retrieving: {}", qrCodeId); return phoneRepository.findByQrCodeId(qrCodeId) - .orElseThrow(() -> new CustomNotFoundExceptions("Phone not found for QR Code id: " + qrCodeId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("Phone not found for QR Code id: " + qrCodeId)); } public void insertDB(PhoneEntity phoneEntity) { phoneRepository.save(phoneEntity); diff --git a/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java b/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java index a1bc94e..a84ccbd 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java @@ -3,7 +3,7 @@ package com.safeqr.app.qrcode.service; import static com.safeqr.app.constants.CommonConstants.*; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.dto.request.QRCodePayload; import com.safeqr.app.qrcode.dto.response.BaseScanResponse; import com.safeqr.app.qrcode.entity.QRCodeEntity; @@ -19,6 +19,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Mono; import java.security.NoSuchAlgorithmException; @@ -69,7 +70,7 @@ public class QRCodeTypeService { public BaseScanResponse getScannedQRCodeDetails(UUID qrCodeId){ // Find scanned qr code in qr code table QRCodeEntity qrCodeEntity = qrCodeRepository.findById(qrCodeId) - .orElseThrow(() -> new CustomNotFoundExceptions("QR Code not found with id: " + qrCodeId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("QR Code not found with id: " + qrCodeId)); logger.info("qrCodeEntity: {}", qrCodeEntity); QRCodeModel qrCodeModel = qrCodeFactoryProvider.createQRCodeInstance(qrCodeEntity); logger.info("Retrieved details: {}", qrCodeModel.getDetails()); @@ -77,6 +78,7 @@ public class QRCodeTypeService { } // Process Scanned QR Code + @Transactional public BaseScanResponse scanQRCode(String userId, QRCodePayload payload) { String data = payload.getData(); logger.info("scanQRCode: userId={}, data={}", userId, data); diff --git a/src/main/java/com/safeqr/app/qrcode/service/SMSVerificationService.java b/src/main/java/com/safeqr/app/qrcode/service/SMSVerificationService.java index 7370a14..90ee218 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/SMSVerificationService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/SMSVerificationService.java @@ -1,6 +1,6 @@ package com.safeqr.app.qrcode.service; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.entity.SMSEntity; import com.safeqr.app.qrcode.repository.SMSRepository; import org.slf4j.Logger; @@ -23,7 +23,7 @@ public class SMSVerificationService { public SMSEntity getSMSEntityByQRCodeId(UUID qrCodeId) { logger.info("qrCodeId retrieving: {}", qrCodeId); return smsRepository.findByQrCodeId(qrCodeId) - .orElseThrow(() -> new CustomNotFoundExceptions("SMS not found for QR Code id: " + qrCodeId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("SMS not found for QR Code id: " + qrCodeId)); } public void insertDB(SMSEntity smsEntity) { smsRepository.save(smsEntity); diff --git a/src/main/java/com/safeqr/app/qrcode/service/TextVerificationService.java b/src/main/java/com/safeqr/app/qrcode/service/TextVerificationService.java index e54b7b5..e1b460c 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/TextVerificationService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/TextVerificationService.java @@ -1,6 +1,6 @@ package com.safeqr.app.qrcode.service; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.entity.TextEntity; import com.safeqr.app.qrcode.repository.TextRepository; import org.slf4j.Logger; @@ -22,7 +22,7 @@ public class TextVerificationService { public TextEntity getTextEntityByQRCodeId(UUID qrCodeId) { logger.info("qrCodeId retrieving: {}", qrCodeId); return textRepository.findByQrCodeId(qrCodeId) - .orElseThrow(() -> new CustomNotFoundExceptions("Text not found for QR Code id: " + qrCodeId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("Text not found for QR Code id: " + qrCodeId)); } public void insertDB(TextEntity textEntity) { textRepository.save(textEntity); diff --git a/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java b/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java index 58adfd6..23d4f60 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java @@ -2,7 +2,7 @@ package com.safeqr.app.qrcode.service; import static com.safeqr.app.constants.CommonConstants.*; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.dto.request.QRCodePayload; import com.safeqr.app.qrcode.dto.URLVerificationResponse; import com.safeqr.app.qrcode.entity.URLEntity; @@ -30,7 +30,7 @@ public class URLVerificationService { public URLEntity getURLEntityByQRCodeId(UUID qrCodeId) { logger.info("qrCodeId retrieving: {}", qrCodeId); return urlRepository.findByQrCodeId(qrCodeId) - .orElseThrow(() -> new CustomNotFoundExceptions("URL not found for QR Code id: " + qrCodeId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("URL not found for QR Code id: " + qrCodeId)); } public void insertDB(URLEntity urlEntity) { diff --git a/src/main/java/com/safeqr/app/qrcode/service/WifiVerificationService.java b/src/main/java/com/safeqr/app/qrcode/service/WifiVerificationService.java index 9b77692..b2c8b62 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/WifiVerificationService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/WifiVerificationService.java @@ -1,6 +1,6 @@ package com.safeqr.app.qrcode.service; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.entity.WifiEntity; import com.safeqr.app.qrcode.repository.WifiRepository; import org.slf4j.Logger; @@ -22,7 +22,7 @@ public class WifiVerificationService { public WifiEntity getWifiEntityByQRCodeId(UUID qrCodeId) { logger.info("qrCodeId retrieving: {}", qrCodeId); return wifiRepository.findByQrCodeId(qrCodeId) - .orElseThrow(() -> new CustomNotFoundExceptions("Wifi not found for QR Code id: " + qrCodeId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("Wifi not found for QR Code id: " + qrCodeId)); } public void insertDB(WifiEntity wifiEntity) { wifiRepository.save(wifiEntity); diff --git a/src/main/java/com/safeqr/app/user/controller/UserController.java b/src/main/java/com/safeqr/app/user/controller/UserController.java index 6dbfbd3..8fe2f8d 100644 --- a/src/main/java/com/safeqr/app/user/controller/UserController.java +++ b/src/main/java/com/safeqr/app/user/controller/UserController.java @@ -4,6 +4,8 @@ import static com.safeqr.app.constants.APIConstants.*; import static com.safeqr.app.constants.CommonConstants.HEADER_USER_ID; import com.safeqr.app.qrcode.entity.QRCodeEntity; +import com.safeqr.app.user.dto.BaseResponse; +import com.safeqr.app.user.dto.BookmarkRequestDto; import com.safeqr.app.user.dto.UserResponseDto; import com.safeqr.app.user.service.UserService; import org.slf4j.Logger; @@ -11,10 +13,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; @@ -47,9 +46,39 @@ public class UserController { return ResponseEntity.ok(userService.getUserScannedHistories(userId)); } + @PutMapping(value = API_URL_USER_DELETE_SCANNED_HISTORIES, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity deleteScannedHistory(@RequestHeader(name = HEADER_USER_ID) String userId, @RequestBody BookmarkRequestDto bookmarkRequestDto) { + logger.info("Invoking PUT Delete Single Scanned History endpoint"); + return ResponseEntity.ok(userService.deleteScannedHistory(userId, bookmarkRequestDto.getQrCodeId())); + } + + @PutMapping(value = API_URL_USER_DELETE_ALL_SCANNED_HISTORIES, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity deleteAllScannedHistories(@RequestHeader(name = HEADER_USER_ID) String userId) { + logger.info("Invoking PUT Delete All Scanned Histories endpoint"); + return ResponseEntity.ok(userService.deleteAllScannedHistoriesByUserId(userId)); + } + @GetMapping(value = API_URL_USER_GET_BOOKMARKS, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity> getUserBookmarks(@RequestHeader(name = HEADER_USER_ID) String userId) { logger.info("Invoking GET User bookmarks endpoint"); return ResponseEntity.ok(userService.getUserBookmarks(userId)); } + + @PostMapping(value = API_URL_USER_SET_BOOKMARK, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity setBookmark(@RequestHeader(name = HEADER_USER_ID) String userId, @RequestBody BookmarkRequestDto bookmarkRequestDto) { + logger.info("Invoking POST User bookmark endpoint"); + return ResponseEntity.ok(userService.setBookmark(userId, bookmarkRequestDto.getQrCodeId())); + } + + @PutMapping(value = API_URL_USER_DELETE_BOOKMARK, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity deleteBookmark(@RequestHeader(name = HEADER_USER_ID) String userId, @RequestBody BookmarkRequestDto bookmarkRequestDto) { + logger.info("Invoking PUT Delete Single Bookmark endpoint"); + return ResponseEntity.ok(userService.deleteBookmark(userId, bookmarkRequestDto.getQrCodeId())); + } + + @PutMapping(value = API_URL_USER_DELETE_ALL_BOOKMARK, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity deleteAllBookmark(@RequestHeader(name = HEADER_USER_ID) String userId) { + logger.info("Invoking PUT Delete All Bookmark endpoint"); + return ResponseEntity.ok(userService.deleteAllBookmarkByUserId(userId)); + } } diff --git a/src/main/java/com/safeqr/app/user/dto/BaseResponse.java b/src/main/java/com/safeqr/app/user/dto/BaseResponse.java new file mode 100644 index 0000000..81bfbf3 --- /dev/null +++ b/src/main/java/com/safeqr/app/user/dto/BaseResponse.java @@ -0,0 +1,11 @@ +package com.safeqr.app.user.dto; + +import lombok.Builder; +import lombok.Data; + + +@Data +@Builder +public class BaseResponse { + private String message; +} diff --git a/src/main/java/com/safeqr/app/user/dto/BookmarkRequestDto.java b/src/main/java/com/safeqr/app/user/dto/BookmarkRequestDto.java new file mode 100644 index 0000000..dc27e85 --- /dev/null +++ b/src/main/java/com/safeqr/app/user/dto/BookmarkRequestDto.java @@ -0,0 +1,10 @@ +package com.safeqr.app.user.dto; + +import lombok.Data; + +import java.util.UUID; + +@Data +public class BookmarkRequestDto { + private UUID qrCodeId; +} diff --git a/src/main/java/com/safeqr/app/user/service/UserService.java b/src/main/java/com/safeqr/app/user/service/UserService.java index 4c42a8a..09db54d 100644 --- a/src/main/java/com/safeqr/app/user/service/UserService.java +++ b/src/main/java/com/safeqr/app/user/service/UserService.java @@ -1,19 +1,30 @@ package com.safeqr.app.user.service; -import com.safeqr.app.exceptions.CustomNotFoundExceptions; +import com.safeqr.app.exceptions.ResourceAlreadyExists; +import com.safeqr.app.exceptions.ResourceNotFoundExceptions; import com.safeqr.app.qrcode.entity.QRCodeEntity; +import com.safeqr.app.qrcode.entity.ScanBookmarkEntity; import com.safeqr.app.qrcode.repository.ScanBookmarkRepository; import com.safeqr.app.qrcode.repository.ScanHistoryRepository; +import com.safeqr.app.user.controller.UserController; +import com.safeqr.app.user.dto.BaseResponse; import com.safeqr.app.user.dto.UserResponseDto; import com.safeqr.app.user.entity.UserEntity; import com.safeqr.app.user.repository.UserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; +import java.util.UUID; @Service public class UserService { + private static final Logger logger = LoggerFactory.getLogger(UserService.class); @Autowired public UserService(UserRepository userRepository, @@ -30,7 +41,7 @@ public class UserService { public UserResponseDto getUserById(String userId) { // Find user by id UserEntity userEntity = userRepository.findById(userId) - .orElseThrow(() -> new CustomNotFoundExceptions("User id not found: " + userId)); + .orElseThrow(() -> new ResourceNotFoundExceptions("User id not found: " + userId)); // Map to DTO before returning to controller return UserResponseDto.builder() @@ -46,7 +57,70 @@ public class UserService { public List getUserScannedHistories(String userId) { return scanHistoryRepository.findAllQRCodesByUserId(userId); } + @Transactional + public BaseResponse deleteScannedHistory(String userId, UUID qrCodeId) { + int updatedCount = scanHistoryRepository.updateScannedHistoryToInactive(userId, qrCodeId); + // throw exception if bookmark not found + if (updatedCount < 1) + throw new ResourceNotFoundExceptions("Scanned QR Code not found"); + + return BaseResponse.builder().message("Scanned QR Code deleted successfully").build(); + } + + @Transactional + public BaseResponse deleteAllScannedHistoriesByUserId(String userId) { + int updatedCount = scanHistoryRepository.updateScannedHistoriesToInactiveByUserId(userId); + + return (updatedCount < 1) ? + BaseResponse.builder().message("No QR Code not found").build(): + BaseResponse.builder().message("All scanned QR Code deleted successfully").build(); + } public List getUserBookmarks(String userId) { return scanBookmarkRepository.findAllBookmarksByUserId(userId); } + @Transactional + public BaseResponse setBookmark(String userId, UUID qrCodeId) { + // Check if the bookmark already exists + Optional existingBookmark = scanBookmarkRepository.findByUserIdAndQrCodeId(userId, qrCodeId); + + // throw exception if bookmark already exists + if (existingBookmark.isPresent()) { + throw new ResourceAlreadyExists("Bookmark already exists!"); + } + try { + // Save bookmark + ScanBookmarkEntity bookmarkEntity = ScanBookmarkEntity.builder() + .userId(userId) + .qrCodeId(qrCodeId) + .bookmarkStatus(ScanBookmarkEntity.BookmarkStatus.ACTIVE) + .build(); + scanBookmarkRepository.save(bookmarkEntity); + + } catch (DataIntegrityViolationException e) { + logger.error("Failed to create bookmark: {}", e.getMessage()); + // throw exception if bookmark creation fails + throw new ResourceNotFoundExceptions("Unable to create bookmark. The QR code may not exist."); + } + + return BaseResponse.builder().message("Bookmark saved successfully").build(); + } + + @Transactional + public BaseResponse deleteBookmark(String userId, UUID qrCodeId) { + int updatedCount = scanBookmarkRepository.updateBookmarkStatusToInactive(userId, qrCodeId); + // throw exception if bookmark not found + if (updatedCount < 1) + throw new ResourceNotFoundExceptions("Bookmark not found"); + + return BaseResponse.builder().message("Bookmark deleted successfully").build(); + } + + @Transactional + public BaseResponse deleteAllBookmarkByUserId(String userId) { + int updatedCount = scanBookmarkRepository.updateBookmarkStatusToInactiveByUserId(userId); + + return (updatedCount < 1) ? + BaseResponse.builder().message("No Bookmark not found").build(): + BaseResponse.builder().message("All Bookmarks deleted successfully").build(); + } }