diff --git a/pom.xml b/pom.xml index 95e4f3f..fe7daef 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,17 @@ spring-boot-starter-data-jpa + + org.projectlombok + lombok + true + + + org.modelmapper + modelmapper + 3.0.0 + + org.springframework.boot diff --git a/src/main/java/com/libraryman_api/book/Book.java b/src/main/java/com/libraryman_api/book/Book.java index b4d3f8e..63ca3e9 100644 --- a/src/main/java/com/libraryman_api/book/Book.java +++ b/src/main/java/com/libraryman_api/book/Book.java @@ -1,9 +1,17 @@ package com.libraryman_api.book; import jakarta.persistence.*; +import lombok.*; + @Entity +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder +@ToString public class Book { @Id @@ -33,91 +41,5 @@ public class Book { @Column(name = "copies_available", nullable = false) private int copiesAvailable; - public Book() { - } - - public Book(String title, String author, String isbn, String publisher, int publishedYear, String genre, int copiesAvailable) { - this.title = title; - this.author = author; - this.isbn = isbn; - this.publisher = publisher; - this.publishedYear = publishedYear; - this.genre = genre; - this.copiesAvailable = copiesAvailable; - } - - public int getBookId() { - return bookId; - } - - public String getTitle() { - return title; - } - - public String getAuthor() { - return author; - } - - public String getIsbn() { - return isbn; - } - - public String getPublisher() { - return publisher; - } - - public int getPublishedYear() { - return publishedYear; - } - - public String getGenre() { - return genre; - } - - public int getCopiesAvailable() { - return copiesAvailable; - } - - - public void setTitle(String title) { - this.title = title; - } - - public void setAuthor(String author) { - this.author = author; - } - - public void setIsbn(String isbn) { - this.isbn = isbn; - } - - public void setPublisher(String publisher) { - this.publisher = publisher; - } - - public void setPublishedYear(int publishedYear) { - this.publishedYear = publishedYear; - } - - public void setGenre(String genre) { - this.genre = genre; - } - - public void setCopiesAvailable(int copiesAvailable) { - this.copiesAvailable = copiesAvailable; - } - @Override - public String toString() { - return "Books{" + - "bookId=" + bookId + - ", title='" + title + '\'' + - ", author='" + author + '\'' + - ", isbn='" + isbn + '\'' + - ", publisher='" + publisher + '\'' + - ", publishedYear=" + publishedYear + - ", genre='" + genre + '\'' + - ", copiesAvailable=" + copiesAvailable + - '}'; - } } diff --git a/src/main/java/com/libraryman_api/book/BookController.java b/src/main/java/com/libraryman_api/book/BookController.java index 778f7c4..b658cd4 100644 --- a/src/main/java/com/libraryman_api/book/BookController.java +++ b/src/main/java/com/libraryman_api/book/BookController.java @@ -23,10 +23,11 @@ public class BookController { /** * Retrieves a list of all books in the library. * - * @return a list of {@link Book} objects representing all the books in the library. + * @return a list of {@link BookDto} objects representing all the books in the library. */ @GetMapping - public List getAllBooks() { + public List getAllBooks() { + return bookService.getAllBooks(); } @@ -34,11 +35,11 @@ public List getAllBooks() { * Retrieves a book by its ID. * * @param id the ID of the book to retrieve. - * @return a {@link ResponseEntity} containing the {@link Book} object, if found. + * @return a {@link ResponseEntity} containing the {@link BookDto} object, if found. * @throws ResourceNotFoundException if the book with the specified ID is not found. */ @GetMapping("/{id}") - public ResponseEntity getBookById(@PathVariable int id) { + public ResponseEntity getBookById(@PathVariable int id) { return bookService.getBookById(id) .map(ResponseEntity::ok) .orElseThrow(() -> new ResourceNotFoundException("Book not found")); @@ -47,24 +48,24 @@ public ResponseEntity getBookById(@PathVariable int id) { /** * Adds a new book to the library. * - * @param book the {@link Book} object representing the new book to add. + * @param bookDto the {@link Book} object representing the new book to add. * @return the added {@link Book} object. */ @PostMapping - public Book addBook(@RequestBody Book book) { - return bookService.addBook(book); + public BookDto addBook(@RequestBody BookDto bookDto) { + return bookService.addBook(bookDto); } /** * Updates an existing book in the library. * * @param id the ID of the book to update. - * @param bookDetails the {@link Book} object containing the updated book details. + * @param bookDtoDetails the {@link Book} object containing the updated book details. * @return the updated {@link Book} object. */ @PutMapping("/{id}") - public Book updateBook(@PathVariable int id, @RequestBody Book bookDetails) { - return bookService.updateBook(id, bookDetails); + public BookDto updateBook(@PathVariable int id, @RequestBody BookDto bookDtoDetails) { + return bookService.updateBook(id, bookDtoDetails); } /** diff --git a/src/main/java/com/libraryman_api/book/BookDto.java b/src/main/java/com/libraryman_api/book/BookDto.java new file mode 100644 index 0000000..5211e0e --- /dev/null +++ b/src/main/java/com/libraryman_api/book/BookDto.java @@ -0,0 +1,34 @@ +package com.libraryman_api.book; + +import jakarta.persistence.Column; +import lombok.*; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Builder +public class BookDto { + + + private int bookId; + + private String title; + + private String author; + + private String isbn; + + private String publisher; + + private int publishedYear; + + private String genre; + + + private int copiesAvailable; + + + +} diff --git a/src/main/java/com/libraryman_api/book/BookService.java b/src/main/java/com/libraryman_api/book/BookService.java index 652f01a..a880fc3 100644 --- a/src/main/java/com/libraryman_api/book/BookService.java +++ b/src/main/java/com/libraryman_api/book/BookService.java @@ -1,6 +1,8 @@ package com.libraryman_api.book; import com.libraryman_api.exception.ResourceNotFoundException; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @@ -25,6 +27,8 @@ public class BookService { private final BookRepository bookRepository; + @Autowired + private ModelMapper mapper; /** * Constructs a new {@code BookService} with the specified {@code BookRepository}. @@ -32,6 +36,7 @@ public class BookService { * @param bookRepository the repository to be used by this service to interact with the database */ public BookService(BookRepository bookRepository) { + this.bookRepository = bookRepository; } @@ -40,8 +45,9 @@ public BookService(BookRepository bookRepository) { * * @return a list of all books */ - public List getAllBooks() { - return bookRepository.findAll(); + public List getAllBooks() { + List allBooks = bookRepository.findAll(); + return allBooks.stream().map(this::EntityToDto).toList(); } /** @@ -50,39 +56,44 @@ public List getAllBooks() { * @param bookId the ID of the book to retrieve * @return an {@code Optional} containing the found book, or {@code Optional.empty()} if no book was found */ - public Optional getBookById(int bookId) { - return bookRepository.findById(bookId); + public Optional getBookById(int bookId) { + + Optional getBook = bookRepository.findById(bookId); + return getBook.map(this::EntityToDto); } /** * Adds a new book to the database. * - * @param book the book to be added + * @param bookDto the book to be added * @return the saved book */ - public Book addBook(Book book) { - return bookRepository.save(book); + public BookDto addBook(BookDto bookDto) { + Book book = DtoToEntity(bookDto); + Book savedBook = bookRepository.save(book); + return EntityToDto(savedBook); } /** * Updates an existing book with the given details. * * @param bookId the ID of the book to update - * @param bookDetails the new details for the book + * @param bookDtoDetails the new details for the book * @return the updated book * @throws ResourceNotFoundException if the book with the specified ID is not found */ - public Book updateBook(int bookId, Book bookDetails) { + public BookDto updateBook(int bookId, BookDto bookDtoDetails) { Book book = bookRepository.findById(bookId) .orElseThrow(() -> new ResourceNotFoundException("Book not found")); - book.setTitle(bookDetails.getTitle()); - book.setAuthor(bookDetails.getAuthor()); - book.setIsbn(bookDetails.getIsbn()); - book.setPublisher(bookDetails.getPublisher()); - book.setPublishedYear(bookDetails.getPublishedYear()); - book.setGenre(bookDetails.getGenre()); - book.setCopiesAvailable(bookDetails.getCopiesAvailable()); - return bookRepository.save(book); + book.setTitle(bookDtoDetails.getTitle()); + book.setAuthor(bookDtoDetails.getAuthor()); + book.setIsbn(bookDtoDetails.getIsbn()); + book.setPublisher(bookDtoDetails.getPublisher()); + book.setPublishedYear(bookDtoDetails.getPublishedYear()); + book.setGenre(bookDtoDetails.getGenre()); + book.setCopiesAvailable(bookDtoDetails.getCopiesAvailable()); + Book updatedBook = bookRepository.save(book); + return EntityToDto(updatedBook); } /** @@ -97,4 +108,13 @@ public void deleteBook(int bookId) { bookRepository.delete(book); } + + + public BookDto EntityToDto(Book book){ + return mapper.map(book,BookDto.class); + } + public Book DtoToEntity(BookDto bookDto){ + return mapper.map(bookDto,Book.class); + } + } diff --git a/src/main/java/com/libraryman_api/borrowing/BorrowingController.java b/src/main/java/com/libraryman_api/borrowing/BorrowingController.java index e76ae53..bd3f5a7 100644 --- a/src/main/java/com/libraryman_api/borrowing/BorrowingController.java +++ b/src/main/java/com/libraryman_api/borrowing/BorrowingController.java @@ -31,19 +31,20 @@ public BorrowingController(BorrowingService borrowingService) { * @return a list of {@link Borrowings} objects representing all borrowings. */ @GetMapping - public List getAllBorrowings() { + public List getAllBorrowings() { + return borrowingService.getAllBorrowings(); } /** * Records a new book borrowing. * - * @param borrowing the {@link Borrowings} object containing borrowing details. + * @param borrowingDto the {@link Borrowings} object containing borrowing details. * @return the saved {@link Borrowings} object representing the borrowing record. */ @PostMapping - public Borrowings borrowBook(@RequestBody Borrowings borrowing) { - return borrowingService.borrowBook(borrowing); + public BorrowingsDto borrowBook(@RequestBody BorrowingsDto borrowingDto) { + return borrowingService.borrowBook(borrowingDto); } /** @@ -52,8 +53,8 @@ public Borrowings borrowBook(@RequestBody Borrowings borrowing) { * @param id the ID of the borrowing record to update. */ @PutMapping("/{id}/return") - public void returnBook(@PathVariable int id) { - borrowingService.returnBook(id); + public BorrowingsDto returnBook(@PathVariable int id) { + return borrowingService.returnBook(id); } /** @@ -75,7 +76,7 @@ public String payFine(@PathVariable int id) { * @return a list of {@link Borrowings} objects representing the member's borrowings. */ @GetMapping("member/{memberId}") - public List getAllBorrowingsOfAMember(@PathVariable int memberId) { + public List getAllBorrowingsOfAMember(@PathVariable int memberId) { return borrowingService.getAllBorrowingsOfMember(memberId); } @@ -87,7 +88,7 @@ public List getAllBorrowingsOfAMember(@PathVariable int memberId) { * @throws ResourceNotFoundException if the borrowing record with the specified ID is not found. */ @GetMapping("{borrowingId}") - public Borrowings getBorrowingById(@PathVariable int borrowingId) { + public BorrowingsDto getBorrowingById(@PathVariable int borrowingId) { return borrowingService.getBorrowingById(borrowingId) .orElseThrow(() -> new ResourceNotFoundException("Borrowing not found")); } diff --git a/src/main/java/com/libraryman_api/borrowing/BorrowingService.java b/src/main/java/com/libraryman_api/borrowing/BorrowingService.java index 668d0cc..c65fe14 100644 --- a/src/main/java/com/libraryman_api/borrowing/BorrowingService.java +++ b/src/main/java/com/libraryman_api/borrowing/BorrowingService.java @@ -1,11 +1,17 @@ package com.libraryman_api.borrowing; +import com.libraryman_api.book.BookDto; import com.libraryman_api.book.BookService; import com.libraryman_api.book.Book; import com.libraryman_api.fine.Fines; import com.libraryman_api.exception.ResourceNotFoundException; import com.libraryman_api.fine.FineRepository; +import com.libraryman_api.member.MemberService; +import com.libraryman_api.member.Members; +import com.libraryman_api.member.MembersDto; import com.libraryman_api.notification.NotificationService; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; @@ -39,20 +45,24 @@ public class BorrowingService { private final FineRepository fineRepository; private final NotificationService notificationService; private final BookService bookService; + private final MemberService memberService; + @Autowired + private ModelMapper mapper; /** * Constructs a new {@code BorrowingService} with the specified repositories and services. * * @param borrowingRepository the repository for managing borrowing records - * @param fineRepository the repository for managing fine records + * @param fineRepository the repository for managing fine records * @param notificationService the service for sending notifications - * @param bookService the service for managing book records + * @param bookService the service for managing book records */ - public BorrowingService(BorrowingRepository borrowingRepository, FineRepository fineRepository, NotificationService notificationService, BookService bookService) { + public BorrowingService(BorrowingRepository borrowingRepository, FineRepository fineRepository, NotificationService notificationService, BookService bookService, MemberService memberService) { this.borrowingRepository = borrowingRepository; this.fineRepository = fineRepository; this.notificationService = notificationService; this.bookService = bookService; + this.memberService = memberService; } /** @@ -60,8 +70,10 @@ public BorrowingService(BorrowingRepository borrowingRepository, FineRepository * * @return a list of all borrowings */ - public List getAllBorrowings() { - return borrowingRepository.findAll(); + public List getAllBorrowings() { + + List borrowings = borrowingRepository.findAll(); + return borrowings.stream().map(borrowing -> mapper.map(borrowing, BorrowingsDto.class)).toList(); } /** @@ -70,8 +82,9 @@ public List getAllBorrowings() { * @param borrowingId the ID of the borrowing to retrieve * @return an {@code Optional} containing the found borrowing, or {@code Optional.empty()} if no borrowing was found */ - public Optional getBorrowingById(int borrowingId) { - return borrowingRepository.findById(borrowingId); + public Optional getBorrowingById(int borrowingId) { + Optional borrowingOptional = borrowingRepository.findById(borrowingId); + return borrowingOptional.map(borrowing -> mapper.map(borrowing, BorrowingsDto.class)); } /** @@ -82,35 +95,68 @@ public Optional getBorrowingById(int borrowingId) { * or roll back in case of any errors. It updates the book's availability, sets the * borrowing and due dates, and sends notifications related to the borrowing.

* - * @param borrowing the borrowing details provided by the user + * @param borrowingDto the borrowing details provided by the user * @return the saved borrowing record * @throws ResourceNotFoundException if the book is not found or if there are not enough copies available */ + @Transactional - public synchronized Borrowings borrowBook(Borrowings borrowing) { - Optional book = bookService.getBookById(borrowing.getBook().getBookId()); + public synchronized BorrowingsDto borrowBook(BorrowingsDto borrowingDto) { + // Retrieve the book by its ID from the borrowingDto + Optional bookDtoOptional = bookService.getBookById(borrowingDto.getBook().getBookId()); - if (book.isPresent()) { - Book bookEntity = book.get(); + if (bookDtoOptional.isPresent()) { + BookDto bookDto = bookDtoOptional.get(); // Fetch the BookDto + + Optional membersDtoOptional = memberService.getMemberById(borrowingDto.getMember().getMemberId()); + if (membersDtoOptional.isPresent()) { + MembersDto membersDto = membersDtoOptional.get(); + + // Check if copies are available + if (bookDto.getCopiesAvailable() > 0) { + // Update the book copies + updateBookCopies(borrowingDto.getBook().getBookId(), "REMOVE", 1); + + // Set borrow date and due date in borrowingDto + borrowingDto.setBorrowDate(new Date()); + borrowingDto.setDueDate(calculateDueDate()); + + // Directly create Borrowings and populate its fields + Borrowings borrowing = new Borrowings(); + borrowing.setBook(mapper.map(bookDto, Book.class));// Map BookDto to Book entity + Members members = mapper.map(membersDto, Members.class); + borrowing.setMember(members); // Map MembersDto to Members entity + borrowing.setBorrowDate(borrowingDto.getBorrowDate()); + borrowing.setDueDate(borrowingDto.getDueDate()); + borrowing.setReturnDate(null); // Set return date if applicable - if (bookEntity.getCopiesAvailable() > 0) { - updateBookCopies(borrowing.getBook().getBookId(), "REMOVE", 1); - borrowing.setBorrowDate(new Date()); - borrowing.setDueDate(calculateDueDate()); + // Save the borrowing record + Borrowings savedBorrowing = borrowingRepository.save(borrowing); - Borrowings savedBorrowing = borrowingRepository.save(borrowing); + // Log saved borrowing for debugging + System.out.println("Saved Borrowing: " + savedBorrowing); - notificationService.borrowBookNotification(savedBorrowing); // Null Book problem - notificationService.reminderNotification(savedBorrowing); // send this notification two days before the due date // Null Book problem - return savedBorrowing; + // Send notifications + notificationService.borrowBookNotification(savedBorrowing); + notificationService.reminderNotification(savedBorrowing); + + // Map and return the saved borrowing as BorrowingsDto + BorrowingsDto resultDto = mapper.map(savedBorrowing, BorrowingsDto.class); + System.out.println("Mapped BorrowingsDto: " + resultDto); // Debugging log + return resultDto; + } else { + throw new ResourceNotFoundException("Not enough copies available"); + } } else { - throw new ResourceNotFoundException("Not enough copies available"); + throw new ResourceNotFoundException("Member not found"); } - } else { + } + else { throw new ResourceNotFoundException("Book not found"); } } + /** * Manages the return process for a borrowed book. * @@ -122,8 +168,8 @@ public synchronized Borrowings borrowBook(Borrowings borrowing) { * @param borrowingId the ID of the borrowing record * @throws ResourceNotFoundException if the borrowing record is not found, if the book has already been returned, or if there are outstanding fines */ - public synchronized void returnBook(int borrowingId) { - Borrowings borrowing = getBorrowingById(borrowingId) + public synchronized BorrowingsDto returnBook(int borrowingId) { + BorrowingsDto borrowing = getBorrowingById(borrowingId) .orElseThrow(() -> new ResourceNotFoundException("Borrowing not found")); if (borrowing.getReturnDate() != null) { @@ -131,8 +177,9 @@ public synchronized void returnBook(int borrowingId) { } if (borrowing.getDueDate().before(new Date())) { if (borrowing.getFine() == null) { - borrowing.setFine(imposeFine(borrowing)); - borrowingRepository.save(borrowing); + Borrowings borrowings = mapper.map(borrowing, Borrowings.class); + borrowing.setFine(imposeFine(borrowings)); + borrowingRepository.save(borrowings); notificationService.fineImposedNotification(borrowing); throw new ResourceNotFoundException("Due date passed. Fine imposed, pay fine first to return the book"); } else if (!borrowing.getFine().isPaid()) { @@ -143,8 +190,10 @@ public synchronized void returnBook(int borrowingId) { borrowing.setReturnDate(new Date()); updateBookCopies(borrowing.getBook().getBookId(), "ADD", 1); - notificationService.bookReturnedNotification(borrowing); - borrowingRepository.save(borrowing); + Borrowings borrowings = mapper.map(borrowing, Borrowings.class); + notificationService.bookReturnedNotification(borrowings); + Borrowings returnedBookRecord = borrowingRepository.save(borrowings); + return mapper.map(returnedBookRecord,BorrowingsDto.class); } /** @@ -170,15 +219,16 @@ private Fines imposeFine(Borrowings borrowing) { * @throws ResourceNotFoundException if the borrowing record is not found or if there is no outstanding fine */ public String payFine(int borrowingId) { - Borrowings borrowing = getBorrowingById(borrowingId) + BorrowingsDto borrowingsDto = getBorrowingById(borrowingId) .orElseThrow(() -> new ResourceNotFoundException("Borrowing not found")); - Fines fine = borrowing.getFine(); + Fines fine = borrowingsDto.getFine(); if (fine != null && !fine.isPaid()) { fine.setPaid(true); - notificationService.finePaidNotification(borrowing); + Borrowings borrowings = mapper.map(borrowingsDto, Borrowings.class); + notificationService.finePaidNotification(borrowings); fineRepository.save(fine); // Save the updated fine - borrowingRepository.save(borrowing); // Save borrowing with updated fine + borrowingRepository.save(borrowings); // Save borrowing with updated fine } else { throw new ResourceNotFoundException("No outstanding fine found or fine already paid"); } @@ -198,10 +248,10 @@ public String payFine(int borrowingId) { * @throws ResourceNotFoundException if the book is not found or if there are not enough copies to remove */ public void updateBookCopies(int bookId, String operation, int numberOfCopies) { - Optional book = bookService.getBookById(bookId); + Optional book = bookService.getBookById(bookId); if (book.isPresent()) { - Book bookEntity = book.get(); + BookDto bookEntity = book.get(); if (operation.equals("ADD")) { bookEntity.setCopiesAvailable(bookEntity.getCopiesAvailable() + numberOfCopies); } else if (operation.equals("REMOVE")) { @@ -252,7 +302,8 @@ private BigDecimal calculateFineAmount(Borrowings borrowing) { * @return a list of borrowings associated with the specified member * @throws ResourceNotFoundException if the member has not borrowed any books */ - public List getAllBorrowingsOfMember(int memberId) { - return borrowingRepository.findByMember_memberId(memberId).orElseThrow(() -> new ResourceNotFoundException("Member didn't borrow any book")); + public List getAllBorrowingsOfMember(int memberId) { + List borrowingsList = borrowingRepository.findByMember_memberId(memberId).orElseThrow(() -> new ResourceNotFoundException("Member didn't borrow any book")); + return borrowingsList.stream().map(borrowings -> mapper.map(borrowings,BorrowingsDto.class)).toList(); } } diff --git a/src/main/java/com/libraryman_api/borrowing/Borrowings.java b/src/main/java/com/libraryman_api/borrowing/Borrowings.java index c562e40..db9fd9c 100644 --- a/src/main/java/com/libraryman_api/borrowing/Borrowings.java +++ b/src/main/java/com/libraryman_api/borrowing/Borrowings.java @@ -4,10 +4,17 @@ import com.libraryman_api.fine.Fines; import com.libraryman_api.member.Members; import jakarta.persistence.*; +import lombok.*; import java.util.Date; @Entity +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString public class Borrowings { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, @@ -30,7 +37,7 @@ public class Borrowings { @JoinColumn(name = "member_id", nullable = false) private Members member; - @Column(name = "borrow_date",nullable = false) + @Column(name = "borrow_date", nullable = false) private Date borrowDate; @Column(name = "due_date", nullable = false) @@ -40,66 +47,4 @@ public class Borrowings { private Date returnDate; - public Borrowings() { - } - - public Borrowings(Book book, Members member, Date borrowDate, Date dueDate, Date returnDate) { - this.book = book; - this.member = member; - this.borrowDate = borrowDate; - this.dueDate = dueDate; - this.returnDate = returnDate; - } - - public Fines getFine() { - return fine; - } - - public void setFine(Fines fine) { - this.fine = fine; - } - - public int getBorrowingId() { - return borrowingId; - } - - public Book getBook() { - return book; - } - - public void setBook(Book book) { - this.book = book; - } - - public Members getMember() { - return member; - } - - public void setMember(Members member) { - this.member = member; - } - - public Date getBorrowDate() { - return borrowDate; - } - - public void setBorrowDate(Date borrowDate) { - this.borrowDate = borrowDate; - } - - public Date getDueDate() { - return dueDate; - } - - public void setDueDate(Date dueDate) { - this.dueDate = dueDate; - } - - public Date getReturnDate() { - return returnDate; - } - - public void setReturnDate(Date returnDate) { - this.returnDate = returnDate; - } } \ No newline at end of file diff --git a/src/main/java/com/libraryman_api/borrowing/BorrowingsDto.java b/src/main/java/com/libraryman_api/borrowing/BorrowingsDto.java new file mode 100644 index 0000000..90a8a82 --- /dev/null +++ b/src/main/java/com/libraryman_api/borrowing/BorrowingsDto.java @@ -0,0 +1,34 @@ +package com.libraryman_api.borrowing; + + +import com.libraryman_api.book.BookDto; +import com.libraryman_api.fine.Fines; +import com.libraryman_api.member.MembersDto; +import lombok.*; +import java.util.Date; +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString + +public class BorrowingsDto { + + + private int borrowingId; + + private BookDto book; + + private Fines fine; + + private MembersDto member; + + private Date borrowDate; + + private Date dueDate; + + private Date returnDate; + + +} diff --git a/src/main/java/com/libraryman_api/email/EmailService.java b/src/main/java/com/libraryman_api/email/EmailService.java index 288723f..5bd0d8e 100644 --- a/src/main/java/com/libraryman_api/email/EmailService.java +++ b/src/main/java/com/libraryman_api/email/EmailService.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.scheduling.annotation.Async; diff --git a/src/main/java/com/libraryman_api/fine/Fines.java b/src/main/java/com/libraryman_api/fine/Fines.java index 48e06c2..7cbfbf3 100644 --- a/src/main/java/com/libraryman_api/fine/Fines.java +++ b/src/main/java/com/libraryman_api/fine/Fines.java @@ -1,10 +1,16 @@ package com.libraryman_api.fine; import jakarta.persistence.*; +import lombok.*; import java.math.BigDecimal; @Entity +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor public class Fines { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, @@ -26,33 +32,4 @@ public class Fines { @Column(nullable = false) private boolean paid = false; - public Fines() { - } - - - public Fines( BigDecimal amount, boolean paid) { - - this.amount = amount; - this.paid = paid; - } - - public BigDecimal getAmount() { - return amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public boolean isPaid() { - return paid; - } - - public void setPaid(boolean paid) { - this.paid = paid; - } - - public int getFineId() { - return fineId; - } } diff --git a/src/main/java/com/libraryman_api/member/MemberController.java b/src/main/java/com/libraryman_api/member/MemberController.java index 246589c..bed41ee 100644 --- a/src/main/java/com/libraryman_api/member/MemberController.java +++ b/src/main/java/com/libraryman_api/member/MemberController.java @@ -31,7 +31,7 @@ public MemberController(MemberService memberService) { * @return a list of {@link Members} representing all members in the library */ @GetMapping - public List getAllMembers() { + public List getAllMembers() { return memberService.getAllMembers(); } @@ -43,7 +43,7 @@ public List getAllMembers() { * @return a {@link ResponseEntity} containing the found {@link Members} object */ @GetMapping("/{id}") - public ResponseEntity getMemberById(@PathVariable int id) { + public ResponseEntity getMemberById(@PathVariable int id) { return memberService.getMemberById(id) .map(ResponseEntity::ok) .orElseThrow(() -> new ResourceNotFoundException("Member not found")); @@ -52,12 +52,13 @@ public ResponseEntity getMemberById(@PathVariable int id) { /** * Adds a new library member. * - * @param member the {@link Members} object representing the new member + * @param memberDto the {@link Members} object representing the new member * @return the added {@link Members} object */ @PostMapping - public Members addMember(@RequestBody Members member) { - return memberService.addMember(member); + public MembersDto addMember(@RequestBody MembersDto memberDto) { + + return memberService.addMember(memberDto); } /** @@ -65,12 +66,12 @@ public Members addMember(@RequestBody Members member) { * If the member is not found, a {@link ResourceNotFoundException} is thrown. * * @param id the ID of the member to update - * @param memberDetails the {@link Members} object containing the updated details + * @param memberDtoDetails the {@link Members} object containing the updated details * @return the updated {@link Members} object */ @PutMapping("/{id}") - public Members updateMember(@PathVariable int id, @RequestBody Members memberDetails) { - return memberService.updateMember(id, memberDetails); + public MembersDto updateMember(@PathVariable int id, @RequestBody MembersDto memberDtoDetails) { + return memberService.updateMember(id, memberDtoDetails); } /** diff --git a/src/main/java/com/libraryman_api/member/MemberService.java b/src/main/java/com/libraryman_api/member/MemberService.java index b73e384..1185bcd 100644 --- a/src/main/java/com/libraryman_api/member/MemberService.java +++ b/src/main/java/com/libraryman_api/member/MemberService.java @@ -2,6 +2,9 @@ import com.libraryman_api.exception.ResourceNotFoundException; import com.libraryman_api.notification.NotificationService; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.Banner; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @@ -26,6 +29,8 @@ public class MemberService { private final MemberRepository memberRepository; private final NotificationService notificationService; + @Autowired + private ModelMapper mapper; /** * Constructs a new {@code MemberService} with the specified repositories and services. @@ -43,8 +48,10 @@ public MemberService(MemberRepository memberRepository, NotificationService noti * * @return a list of all members */ - public List getAllMembers() { - return memberRepository.findAll(); + public List getAllMembers() { + + List membersList = memberRepository.findAll(); + return membersList.stream().map(members -> mapper.map(members,MembersDto.class)).toList(); } /** @@ -53,8 +60,10 @@ public List getAllMembers() { * @param memberId the ID of the member to retrieve * @return an {@code Optional} containing the found member, or {@code Optional.empty()} if no member was found */ - public Optional getMemberById(int memberId) { - return memberRepository.findById(memberId); + public Optional getMemberById(int memberId) { + + Optional member = memberRepository.findById(memberId); + return member.map(member1 -> mapper.map(member1,MembersDto.class)); } /** @@ -63,14 +72,15 @@ public Optional getMemberById(int memberId) { *

This method saves the new member record in the database and sends a notification * about the account creation.

* - * @param member the member details to be added + * @param memberDto the member details to be added * @return the saved member record */ - public Members addMember(Members member) { + public MembersDto addMember(MembersDto memberDto) { + Members member = mapper.map(memberDto, Members.class); Members currentMember = memberRepository.save(member); notificationService.accountCreatedNotification(currentMember); + return mapper.map(currentMember, MembersDto.class); - return currentMember; } /** @@ -81,21 +91,21 @@ public Members addMember(Members member) { * a notification about the account details update is sent.

* * @param memberId the ID of the member to update - * @param memberDetails the updated member details + * @param memberDtoDetails the updated member details * @return the updated member record * @throws ResourceNotFoundException if the member is not found */ - public Members updateMember(int memberId, Members memberDetails) { + public MembersDto updateMember(int memberId, MembersDto memberDtoDetails) { Members member = memberRepository.findById(memberId) .orElseThrow(() -> new ResourceNotFoundException("Member not found")); - member.setName(memberDetails.getName()); - member.setEmail(memberDetails.getEmail()); - member.setPassword(memberDetails.getPassword()); - member.setRole(memberDetails.getRole()); - member.setMembershipDate(memberDetails.getMembershipDate()); - member = memberRepository.save(member); - notificationService.accountDetailsUpdateNotification(member); - return member; + member.setName(memberDtoDetails.getName()); + member.setEmail(memberDtoDetails.getEmail()); + member.setPassword(memberDtoDetails.getPassword()); + member.setRole(memberDtoDetails.getRole()); + member.setMembershipDate(memberDtoDetails.getMembershipDate()); + Members updateMember = memberRepository.save(member); + notificationService.accountDetailsUpdateNotification(updateMember); + return mapper.map(updateMember,MembersDto.class); } /** diff --git a/src/main/java/com/libraryman_api/member/Members.java b/src/main/java/com/libraryman_api/member/Members.java index f11b805..1bbfa78 100644 --- a/src/main/java/com/libraryman_api/member/Members.java +++ b/src/main/java/com/libraryman_api/member/Members.java @@ -1,11 +1,17 @@ package com.libraryman_api.member; import jakarta.persistence.*; +import lombok.*; import java.util.Date; @Entity +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor public class Members { @Id @@ -34,59 +40,4 @@ public class Members { private Date membershipDate; - - public Members() { - } - - public Members(String name, String email, String password, Role role, Date membershipDate) { - this.name = name; - this.email = email; - this.password = password; - this.role = role; - this.membershipDate = membershipDate; - } - - public int getMemberId() { - return memberId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public Role getRole() { - return role; - } - - public void setRole(Role role) { - this.role = role; - } - - public Date getMembershipDate() { - return membershipDate; - } - - public void setMembershipDate(Date membershipDate) { - this.membershipDate = membershipDate; - } } diff --git a/src/main/java/com/libraryman_api/member/MembersDto.java b/src/main/java/com/libraryman_api/member/MembersDto.java new file mode 100644 index 0000000..4a4c748 --- /dev/null +++ b/src/main/java/com/libraryman_api/member/MembersDto.java @@ -0,0 +1,29 @@ +package com.libraryman_api.member; + +import jakarta.persistence.*; +import lombok.*; + +import java.util.Date; +@Getter +@Setter +@Builder +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class MembersDto { + + private int memberId; + + private String name; + + private String email; + + private String password; + + private Role role; + + private Date membershipDate; + + + +} diff --git a/src/main/java/com/libraryman_api/notification/NotificationService.java b/src/main/java/com/libraryman_api/notification/NotificationService.java index 1d37dde..51f1e3e 100644 --- a/src/main/java/com/libraryman_api/notification/NotificationService.java +++ b/src/main/java/com/libraryman_api/notification/NotificationService.java @@ -1,10 +1,13 @@ package com.libraryman_api.notification; import com.libraryman_api.borrowing.Borrowings; +import com.libraryman_api.borrowing.BorrowingsDto; import com.libraryman_api.email.EmailSender; import com.libraryman_api.exception.ResourceNotFoundException; import com.libraryman_api.member.MemberRepository; import com.libraryman_api.member.Members; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.sql.Timestamp; @@ -25,6 +28,8 @@ public class NotificationService { private final EmailSender emailSender; private final NotificationRepository notificationRepository; private final MemberRepository memberRepository; + @Autowired + private ModelMapper mapper; /** * Constructs a new {@code NotificationService} with the specified {@link EmailSender}, @@ -137,17 +142,17 @@ public void finePaidNotification(Borrowings borrowing) { /** * Sends a notification to a member when a fine is imposed for the late return of a borrowed book. * - * @param borrowing the borrowing instance containing information about the overdue book and the fine imposed. + * @param borrowingsDto the borrowing instance containing information about the overdue book and the fine imposed. */ - public void fineImposedNotification(Borrowings borrowing) { + public void fineImposedNotification(BorrowingsDto borrowingsDto) { Notifications notification = new Notifications(); - notification.setMember(borrowing.getMember()); + notification.setMember(mapper.map(borrowingsDto.getMember(),Members.class)); notification.setMessage("We hope you enjoyed reading '" + - borrowing.getBook().getTitle() + + borrowingsDto.getBook().getTitle() + "'. Unfortunately, our records show that the book was returned after the due date of " + - LocalDateTime.ofInstant(borrowing.getDueDate().toInstant(), ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy HH:mm")) + + LocalDateTime.ofInstant(borrowingsDto.getDueDate().toInstant(), ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy HH:mm")) + ". As a result, a fine of ₹10 per day has been imposed for the late return.

The total fine amount for this overdue return is ₹" + - borrowing.getFine().getAmount() + + borrowingsDto.getFine().getAmount() + ".

If you have any questions or would like to discuss this matter further, please don't hesitate to contact us.

Thank you for your understanding and for being a valued member of our library."); notification.setNotificationType(NotificationType.FINE); notification.setSentDate(new Timestamp(System.currentTimeMillis())); diff --git a/src/main/java/com/libraryman_api/notification/Notifications.java b/src/main/java/com/libraryman_api/notification/Notifications.java index 3ef9cb6..66e6603 100644 --- a/src/main/java/com/libraryman_api/notification/Notifications.java +++ b/src/main/java/com/libraryman_api/notification/Notifications.java @@ -2,9 +2,17 @@ import com.libraryman_api.member.Members; import jakarta.persistence.*; +import lombok.*; + import java.sql.Timestamp; @Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ToString public class Notifications { @Id @@ -32,58 +40,4 @@ public class Notifications { - public Notifications() { - } - - public Notifications(Members member, String message, NotificationType notificationType, Timestamp sentDate, NotificationStatus notificationStatus) { - this.member = member; - this.message = message; - this.notificationType = notificationType; - this.sentDate = sentDate; - this.notificationStatus = notificationStatus; - } - - public int getNotificationId() { - return notificationId; - } - - public Members getMember() { - return member; - } - - public void setMember(Members member) { - this.member = member; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public NotificationType getNotificationType() { - return notificationType; - } - - public void setNotificationType(NotificationType notificationType) { - this.notificationType = notificationType; - } - - public Timestamp getSentDate() { - return sentDate; - } - - public void setSentDate(Timestamp sentDate) { - this.sentDate = sentDate; - } - - public NotificationStatus getNotificationStatus() { - return notificationStatus; - } - - public void setNotificationStatus(NotificationStatus notificationStatus) { - this.notificationStatus = notificationStatus; - } } diff --git a/src/main/java/com/libraryman_api/projectConfig/ProjectConfiguration.java b/src/main/java/com/libraryman_api/projectConfig/ProjectConfiguration.java new file mode 100644 index 0000000..7b7db47 --- /dev/null +++ b/src/main/java/com/libraryman_api/projectConfig/ProjectConfiguration.java @@ -0,0 +1,13 @@ +package com.libraryman_api.projectConfig; + +import org.modelmapper.ModelMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ProjectConfiguration { + @Bean + public ModelMapper mapper(){ + return new ModelMapper(); + } +} diff --git a/src/main/resources/application-development.properties b/src/main/resources/application-development.properties index c3cf3e5..462665c 100644 --- a/src/main/resources/application-development.properties +++ b/src/main/resources/application-development.properties @@ -4,42 +4,45 @@ ## Make this file as it was earlier before commiting code # Change this connection string to this format: jdbc:mysql://{ip_address}:{port}/{database_name} -spring.datasource.url=jdbc:mysql://localhost:3306/Add_Your_Database_Name +spring.datasource.url=jdbc:mysql://localhost:3306/DATABASE NAME ## Add your Database Username and Password -spring.datasource.username=Add_Your_UserName -spring.datasource.password=Add_Your_Password +spring.datasource.username=ADD_YOUR_USERNAME +spring.datasource.password=ADD_YOUR_PASSWORD # Hibernate Dialect for MySQL 8 spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect # Prevent early database interaction -spring.jpa.properties.hibernate.boot.allow_jdbc_metadata_access=false +#spring.jpa.properties.hibernate.boot.allow_jdbc_metadata_access=false spring.jpa.hibernate.ddl-auto=update -spring.sql.init.mode=never +spring.jpa.show-sql=true +#spring.sql.init.mode=never # Format SQL -spring.jpa.properties.hibernate.format_sql=true +#spring.jpa.properties.hibernate.format_sql=true # Error Handling -server.error.include-binding-errors=always -server.error.include-message=always -server.error.include-stacktrace=never -server.error.include-exception=true +#server.error.include-binding-errors=always +#server.error.include-message=always +#server.error.include-stacktrace=never +#server.error.include-exception=true # Logging for Spring Security -logging.level.org.springframework.security=TRACE - +#logging.level.org.springframework.security=TRACE # --- Mail Service Setup --- # I use docker mail service https://hub.docker.com/r/maildev/maildev # Or Web based Mail service https://mailtrap.io/ -spring.mail.host=Add_Your_Mail_Service_Host -spring.mail.port=Add_Your_Mail_Service_Port -spring.mail.username=Add_Your_Mail_Service_Username -spring.mail.password=Add_Your_Mail_Service_Password -spring.mail.properties.mail.smtp.auth=Add_Your_Mail_Service_SMTP -spring.mail.properties.mail.starttls.enable=Add_Your_Mail_Service_Start_TLS -spring.mail.properties.domain_name=Add_Your_Mail_Service_Domain_Name \ No newline at end of file +#spring.mail.host=Add_Your_Mail_Service_Host +#spring.mail.port=Add_Your_Mail_Service_Port +#spring.mail.username=Add_Your_Mail_Service_Username +#spring.mail.password=Add_Your_Mail_Service_Password +#spring.mail.properties.mail.smtp.auth=Add_Your_Mail_Service_SMTP +#spring.mail.properties.mail.starttls.enable=Add_Your_Mail_Service_Start_TLS +#spring.mail.properties.domain_name=Add_Your_Mail_Service_Domain_Name + + + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index eeefb5c..0530635 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,3 @@ spring.application.name=libraryman-api -spring.profiles.active=${ENV:dev} \ No newline at end of file +#spring.profiles.active=${ENV:dev} +spring.profiles.active=development \ No newline at end of file