Add MongoDB integration

This commit is contained in:
Alex Selimov 2025-04-13 16:27:03 -04:00
parent 3a3f488841
commit b4c8aaa4e8
8 changed files with 288 additions and 5 deletions

View File

@ -1,20 +1,71 @@
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.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
@RequestMapping("/api/notifications")
public class NotificationController {
private final NotificationService notificationService;
@Autowired
public NotificationController(final NotificationService notificationService) {
this.notificationService = notificationService;
}
@PostMapping
public ResponseEntity<String> createNotification(@RequestBody Notification notification) {
return ResponseEntity.ok("Notification received: " + notification.getSubject());
public ResponseEntity<Notification> createNotification(@RequestBody final Notification notification) {
final Notification savedNotification = notificationService.saveNotification(notification);
return new ResponseEntity<Notification>(savedNotification, HttpStatus.CREATED);
}
@GetMapping("/health")
public ResponseEntity<String> healthCheck() {
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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -1,6 +1,10 @@
spring.application.name=NS
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.consumer.group-id=notification-group

View File

@ -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());
}
}

View File

@ -0,0 +1 @@
spring.data.mongodb.database=notification-system-test