Add MongoDB integration
This commit is contained in:
parent
3a3f488841
commit
b4c8aaa4e8
@ -1,20 +1,71 @@
|
|||||||
package com.aselimov.NS.controller;
|
package com.aselimov.NS.controller;
|
||||||
|
|
||||||
import com.aselimov.NS.model.Notification;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.aselimov.NS.model.Notification;
|
||||||
|
import com.aselimov.NS.service.NotificationService;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/notifications")
|
@RequestMapping("/api/notifications")
|
||||||
public class NotificationController {
|
public class NotificationController {
|
||||||
|
|
||||||
|
private final NotificationService notificationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public NotificationController(final NotificationService notificationService) {
|
||||||
|
this.notificationService = notificationService;
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<String> createNotification(@RequestBody Notification notification) {
|
public ResponseEntity<Notification> createNotification(@RequestBody final Notification notification) {
|
||||||
return ResponseEntity.ok("Notification received: " + notification.getSubject());
|
final Notification savedNotification = notificationService.saveNotification(notification);
|
||||||
|
return new ResponseEntity<Notification>(savedNotification, HttpStatus.CREATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/health")
|
@GetMapping("/health")
|
||||||
public ResponseEntity<String> healthCheck() {
|
public ResponseEntity<String> healthCheck() {
|
||||||
return ResponseEntity.ok("Notification service running...");
|
return ResponseEntity.ok("Notification service running...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<List<Notification>> getAllNotifications() {
|
||||||
|
return ResponseEntity.ok(notificationService.getAllNotifications());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResponseEntity<Notification> getNotificationById(@PathVariable final String id) {
|
||||||
|
return ResponseEntity.ok(notificationService.getNotificationByIdOrThrow(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/status/{status}")
|
||||||
|
public ResponseEntity<List<Notification>> getNotificationsByStatus(
|
||||||
|
@PathVariable final Notification.NotificationStatus status) {
|
||||||
|
return ResponseEntity.ok(notificationService.getNotificationsByStatus(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/status")
|
||||||
|
public ResponseEntity<Void> updateNotificationStatus(@PathVariable final String id,
|
||||||
|
@RequestParam final Notification.NotificationStatus status) {
|
||||||
|
notificationService.updateNotificationStatus(id, status);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ResponseEntity<Void> deleteNotification(@PathVariable String id) {
|
||||||
|
notificationService.deleteNotification(id);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.aselimov.NS.exception;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
@ExceptionHandler(NotificationNotFoundException.class)
|
||||||
|
public ResponseEntity<Object> handleNotificationNotFoundException(NotificationNotFoundException ex) {
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("timestamp", LocalDateTime.now());
|
||||||
|
body.put("message", ex.getMessage());
|
||||||
|
|
||||||
|
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public ResponseEntity<Object> handleGlobalException(Exception ex) {
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("timestamp", LocalDateTime.now());
|
||||||
|
body.put("message", "An unexpected error occured");
|
||||||
|
body.put("error", ex.getMessage());
|
||||||
|
|
||||||
|
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.aselimov.NS.exception;
|
||||||
|
|
||||||
|
public class NotificationNotFoundException extends RuntimeException {
|
||||||
|
public NotificationNotFoundException(String id) {
|
||||||
|
super("Notification not found with id:" + id);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.aselimov.NS.repository;
|
||||||
|
|
||||||
|
import com.aselimov.NS.model.Notification;
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface NotificationRepository extends MongoRepository<Notification, String> {
|
||||||
|
// Find notifications by status
|
||||||
|
List<Notification> findByStatus(Notification.NotificationStatus status);
|
||||||
|
|
||||||
|
// Find notifications by type
|
||||||
|
List<Notification> findByType(Notification.NotificationType type);
|
||||||
|
|
||||||
|
// Find notifications by recipient
|
||||||
|
List<Notification> findByRecipient(String recipient);
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.aselimov.NS.service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.aselimov.NS.exception.NotificationNotFoundException;
|
||||||
|
import com.aselimov.NS.model.Notification;
|
||||||
|
import com.aselimov.NS.repository.NotificationRepository;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class NotificationService {
|
||||||
|
private final NotificationRepository notificationRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public NotificationService(NotificationRepository notificationRepository) {
|
||||||
|
this.notificationRepository = notificationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Notification saveNotification(Notification notification) {
|
||||||
|
// Set timestamps if not present
|
||||||
|
if (notification.getCreatedAt() == null) {
|
||||||
|
notification.setCreatedAt(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
notification.setUpdatedAt(LocalDateTime.now());
|
||||||
|
|
||||||
|
// Ensure status is set
|
||||||
|
if (notification.getStatus() == null) {
|
||||||
|
notification.setStatus(Notification.NotificationStatus.PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
return notificationRepository.save(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Notification> getAllNotifications() {
|
||||||
|
return notificationRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Notification getNotificationByIdOrThrow(String id) {
|
||||||
|
return notificationRepository.findById(id).orElseThrow(() -> new NotificationNotFoundException(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Notification> getNotificationsByStatus(Notification.NotificationStatus status) {
|
||||||
|
return notificationRepository.findByStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Notification> getNotificationsByType(Notification.NotificationType type) {
|
||||||
|
return notificationRepository.findByType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Notification> getNotificationsByRecipient(String recipient) {
|
||||||
|
return notificationRepository.findByRecipient(recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateNotificationStatus(String id, Notification.NotificationStatus status) {
|
||||||
|
notificationRepository.findById(id).ifPresent(notification -> {
|
||||||
|
notification.setStatus(status);
|
||||||
|
notification.setUpdatedAt(LocalDateTime.now());
|
||||||
|
notificationRepository.save(notification);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteNotification(String id) {
|
||||||
|
notificationRepository.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,10 @@
|
|||||||
spring.application.name=NS
|
spring.application.name=NS
|
||||||
|
|
||||||
server.port=8080
|
server.port=8080
|
||||||
spring.data.mongodb.uri=mongodb://localhost:27017/notification-system
|
|
||||||
|
spring.data.mongodb.host=localhost
|
||||||
|
spring.data.mongodb.port=27017
|
||||||
|
spring.data.mongodb.database=notification-system
|
||||||
|
|
||||||
spring.kafka.bootstrap-servers=localhost:9092
|
spring.kafka.bootstrap-servers=localhost:9092
|
||||||
spring.kafka.consumer.group-id=notification-group
|
spring.kafka.consumer.group-id=notification-group
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
package com.aselimov.NS.repository;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
|
||||||
|
import com.aselimov.NS.model.Notification;
|
||||||
|
import com.aselimov.NS.model.Notification.NotificationType;
|
||||||
|
|
||||||
|
@DataMongoTest
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
public class NotificationRepositoryTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
notificationRepository.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationRepository getNotificationRepository() {
|
||||||
|
return notificationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private NotificationRepository notificationRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSaveNotification() {
|
||||||
|
// Given
|
||||||
|
final Notification notification = new Notification();
|
||||||
|
notification.setType(Notification.NotificationType.EMAIL);
|
||||||
|
notification.setRecipient("test@example.com");
|
||||||
|
notification.setSubject("Test Subject");
|
||||||
|
notification.setContent("Test Content");
|
||||||
|
notification.setStatus(Notification.NotificationStatus.PENDING);
|
||||||
|
notification.setCreatedAt(LocalDateTime.now());
|
||||||
|
notification.setUpdatedAt(LocalDateTime.now());
|
||||||
|
|
||||||
|
// When
|
||||||
|
Notification savedNotification = notificationRepository.save(notification);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assert (savedNotification.getId() != null) : "Notification shouldn't be null";
|
||||||
|
assertEquals(Notification.NotificationType.EMAIL, savedNotification.getType());
|
||||||
|
assertEquals("test@example.com", savedNotification.getRecipient());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFindByStatus() {
|
||||||
|
// Given
|
||||||
|
Notification notification1 = new Notification();
|
||||||
|
notification1.setType(Notification.NotificationType.EMAIL);
|
||||||
|
notification1.setRecipient("test1@example.com");
|
||||||
|
notification1.setStatus(Notification.NotificationStatus.PENDING);
|
||||||
|
notification1.setCreatedAt(LocalDateTime.now());
|
||||||
|
notification1.setUpdatedAt(LocalDateTime.now());
|
||||||
|
|
||||||
|
Notification notification2 = new Notification();
|
||||||
|
notification2.setType(Notification.NotificationType.SMS);
|
||||||
|
notification2.setRecipient("test2@example.com");
|
||||||
|
notification2.setStatus(Notification.NotificationStatus.SENT);
|
||||||
|
notification2.setCreatedAt(LocalDateTime.now());
|
||||||
|
notification2.setUpdatedAt(LocalDateTime.now());
|
||||||
|
|
||||||
|
notificationRepository.saveAll(List.of(notification1, notification2));
|
||||||
|
|
||||||
|
// When
|
||||||
|
List<Notification> pendingNotifications = notificationRepository
|
||||||
|
.findByStatus(Notification.NotificationStatus.PENDING);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(1, pendingNotifications.size());
|
||||||
|
assertEquals("test1@example.com", pendingNotifications.get(0).getRecipient());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFindByType() {
|
||||||
|
// Given
|
||||||
|
Notification notification = new Notification();
|
||||||
|
notification.setType(Notification.NotificationType.PUSH);
|
||||||
|
notification.setRecipient("test@example.com");
|
||||||
|
notification.setStatus(Notification.NotificationStatus.PENDING);
|
||||||
|
notification.setCreatedAt(LocalDateTime.now());
|
||||||
|
notification.setUpdatedAt(LocalDateTime.now());
|
||||||
|
|
||||||
|
notificationRepository.save(notification);
|
||||||
|
|
||||||
|
// When
|
||||||
|
List<Notification> pushNotifications = notificationRepository.findByType(NotificationType.PUSH);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(1, pushNotifications.size());
|
||||||
|
assertEquals(NotificationType.PUSH, pushNotifications.get(0).getType());
|
||||||
|
}
|
||||||
|
}
|
1
src/test/resources/application-test.properties
Normal file
1
src/test/resources/application-test.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
spring.data.mongodb.database=notification-system-test
|
Loading…
x
Reference in New Issue
Block a user