Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Security Branch into Main: Resolve Conflicts and Integrate JWT and OAuth2 Features #74

Merged
merged 17 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 50 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com</groupId>
<artifactId>libraryman-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>libraryman-api</name>
<description>Revolutionize book management with LibraryMan! Easily track stock, borrowers, and due dates, streamlining operations for schools, companies, and libraries worldwide, ensuring efficient and organized book lending.</description>
<url/>
<description>Revolutionize book management with LibraryMan! Easily track
stock, borrowers, and due dates, streamlining operations for schools,
companies, and libraries worldwide, ensuring efficient and organized
book lending.</description>
<url />
<licenses>
<license/>
<license />
</licenses>
<developers>
<developer/>
<developer />
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
<connection />
<developerConnection />
<tag />
<url />
</scm>
<properties>
<java.version>17</java.version>
Expand All @@ -47,6 +51,26 @@
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>com.mysql</groupId>
Expand All @@ -67,9 +91,24 @@

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ public static void main(String[] args) {
SpringApplication.run(LibrarymanApiApplication.class, args);
}

}
}
4 changes: 4 additions & 0 deletions src/main/java/com/libraryman_api/book/BookController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

/**
Expand Down Expand Up @@ -71,6 +72,7 @@ public ResponseEntity<BookDto> getBookById(@PathVariable int id) {
* @return the added {@link Book} object.
*/
@PostMapping
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public BookDto addBook(@RequestBody BookDto bookDto) {
return bookService.addBook(bookDto);
}
Expand All @@ -83,6 +85,7 @@ public BookDto addBook(@RequestBody BookDto bookDto) {
* @return the updated {@link Book} object.
*/
@PutMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public BookDto updateBook(@PathVariable int id, @RequestBody BookDto bookDtoDetails) {
return bookService.updateBook(id, bookDtoDetails);
}
Expand All @@ -93,6 +96,7 @@ public BookDto updateBook(@PathVariable int id, @RequestBody BookDto bookDtoDeta
* @param id the ID of the book to delete.
*/
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public void deleteBook(@PathVariable int id) {
bookService.deleteBook(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.libraryman_api.exception.ResourceNotFoundException;

import org.springframework.security.access.prepost.PreAuthorize;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -39,6 +41,7 @@ public BorrowingController(BorrowingService borrowingService) {
* The results are sorted by borrow date by default and limited to 5 members per page.
*/
@GetMapping
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public Page<BorrowingsDto> getAllBorrowings(@PageableDefault(page=0, size=5, sort="borrowDate") Pageable pageable,
@RequestParam(required = false) String sortBy,
@RequestParam(required = false) String sortDir) {
Expand All @@ -64,6 +67,7 @@ public Page<BorrowingsDto> getAllBorrowings(@PageableDefault(page=0, size=5, sor
* @return the saved {@link Borrowings} object representing the borrowing record.
*/
@PostMapping
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN') or (hasRole('USER') and #borrowingsDto.member.memberId == authentication.principal.memberId)")
public BorrowingsDto borrowBook(@RequestBody BorrowingsDto borrowingsDto) {
return borrowingService.borrowBook(borrowingsDto);
}
Expand Down Expand Up @@ -101,6 +105,7 @@ public String payFine(@PathVariable int id) {
* The results are sorted by borrow date by default and limited to 5 members per page.
*/
@GetMapping("member/{memberId}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN') or (hasRole('USER') and #memberId == authentication.principal.memberId)")
public Page<BorrowingsDto> getAllBorrowingsOfAMember(@PathVariable int memberId,
@PageableDefault(page=0, size=5, sort="borrowDate") Pageable pageable,
@RequestParam(required = false) String sortBy,
Expand Down Expand Up @@ -128,6 +133,7 @@ public Page<BorrowingsDto> getAllBorrowingsOfAMember(@PathVariable int memberId,
* @throws ResourceNotFoundException if the borrowing record with the specified ID is not found.
*/
@GetMapping("{borrowingId}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public BorrowingsDto getBorrowingById(@PathVariable int borrowingId) {
return borrowingService.getBorrowingById(borrowingId)
.orElseThrow(() -> new ResourceNotFoundException("Borrowing not found"));
Expand Down
15 changes: 4 additions & 11 deletions src/main/java/com/libraryman_api/member/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

/**
Expand Down Expand Up @@ -39,6 +40,7 @@ public MemberController(MemberService memberService) {
* The results are sorted by name by default and limited to 5 members per page.
*/
@GetMapping
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public Page<MembersDto> getAllMembers(@PageableDefault(page=0, size=5, sort="name") Pageable pageable,
@RequestParam(required = false) String sortBy,
@RequestParam(required = false) String sortDir) {
Expand All @@ -65,23 +67,13 @@ public Page<MembersDto> getAllMembers(@PageableDefault(page=0, size=5, sort="nam
* @return a {@link ResponseEntity} containing the found {@link Members} object
*/
@GetMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public ResponseEntity<MembersDto> getMemberById(@PathVariable int id) {
return memberService.getMemberById(id)
.map(ResponseEntity::ok)
.orElseThrow(() -> new ResourceNotFoundException("Member not found"));
}

/**
* Adds a new library member.
*
* @param membersDto the {@link Members} object representing the new member
* @return the added {@link Members} object
*/
@PostMapping
public MembersDto addMember(@RequestBody MembersDto membersDto) {
return memberService.addMember(membersDto);
}

/**
* Updates an existing library member.
* If the member is not found, a {@link ResourceNotFoundException} is thrown.
Expand All @@ -102,6 +94,7 @@ public MembersDto updateMember(@PathVariable int id, @RequestBody MembersDto mem
* @param id the ID of the member to delete
*/
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public void deleteMember(@PathVariable int id) {
memberService.deleteMember(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface MemberRepository extends JpaRepository<Members, Integer> {

Optional<Members> findByMemberId(int memberId);

Optional<Members> findByUsername(String username);

/**
* SELECT SUM(amount) AS totalFines
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/com/libraryman_api/member/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public MembersDto updateMember(int memberId, MembersDto membersDtoDetails) {
Members member = memberRepository.findById(memberId)
.orElseThrow(() -> new ResourceNotFoundException("Member not found"));
member.setName(membersDtoDetails.getName());
member.setUsername(membersDtoDetails.getUsername());
member.setEmail(membersDtoDetails.getEmail());
member.setPassword(membersDtoDetails.getPassword());
member.setRole(membersDtoDetails.getRole());
Expand All @@ -133,7 +134,6 @@ public MembersDto updateMember(int memberId, MembersDto membersDtoDetails) {
* @param memberId the ID of the member to delete
* @throws ResourceNotFoundException if the member is not found
*/

@CacheEvict(value = "members", key = "#memberId")
public void deleteMember(int memberId) {
Members member = memberRepository.findById(memberId)
Expand All @@ -145,45 +145,45 @@ public void deleteMember(int memberId) {
notificationService.accountDeletionNotification(member);
memberRepository.delete(member);
}

/**
* Converts a MembersDto object to a Members entity.
*
* <p>This method takes a MembersDto object and transforms it into a Members entity
* to be used in database operations. It maps all relevant member details from
* the DTO, including member ID, role, name, email, password, and membership date.</p>
* the DTO, including member ID, role, name, username, email, password, and membership date.</p>
*
* @param membersDto the DTO object containing member information
* @return a Members entity with data populated from the DTO
*/


public Members DtoEntity(MembersDto membersDto){
Members members= new Members();
members.setMemberId(membersDto.getMemberId());
members.setRole(membersDto.getRole());
members.setName(membersDto.getName());
members.setUsername(membersDto.getUsername());
members.setEmail(membersDto.getEmail());
members.setPassword(membersDto.getPassword());
members.setMembershipDate(membersDto.getMembershipDate());
return members;
}

/**
* Converts a Members entity to a MembersDto object.
*
* <p>This method takes a Members entity object and converts it into a MembersDto
* object to be used for data transfer between layers. It maps all necessary
* member details, including member ID, name, role, email, password, and membership
* member details, including member ID, name, username, role, email, password, and membership
* date, from the entity to the DTO.</p>
*
* @param members the entity object containing member information
* @return a MembersDto object with data populated from the entity
*/


public MembersDto EntityToDto(Members members){
MembersDto membersDto= new MembersDto();
membersDto.setMemberId(members.getMemberId());
membersDto.setName(members.getName());
membersDto.setUsername(members.getUsername());
membersDto.setRole(members.getRole());
membersDto.setEmail(members.getEmail());
membersDto.setPassword(members.getPassword());
Expand Down
27 changes: 26 additions & 1 deletion src/main/java/com/libraryman_api/member/Members.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

import jakarta.persistence.*;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;


@Entity
public class Members {
public class Members implements UserDetails{

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
Expand All @@ -20,6 +26,9 @@ public class Members {
@Column(nullable = false)
private String name;

@Column(name = "username")
private String username;

@Column(unique = true, nullable = false)
private String email;

Expand All @@ -33,6 +42,7 @@ public class Members {
@Column(name = "membership_date")
private Date membershipDate;




public Members() {
Expand Down Expand Up @@ -91,4 +101,19 @@ public Date getMembershipDate() {
public void setMembershipDate(Date membershipDate) {
this.membershipDate = membershipDate;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return Collections.singletonList(new SimpleGrantedAuthority("ROLE_"+role.name()));
}

}
Loading
Loading