diff --git a/API/Controllers/BooksController.cs b/API/Controllers/BooksController.cs index 7dc8379..c9102c3 100644 --- a/API/Controllers/BooksController.cs +++ b/API/Controllers/BooksController.cs @@ -26,19 +26,19 @@ public BooksController(IUnitOfWork unitOfWork, IBibliotekaNarodowaBooksService b } [HttpPost] - public async Task> AddBookToCollection(AddBookDto addBookDto) + public async Task> AddBookToCollection(AddBookDto addBookDto, CancellationToken ct) { var userId = User.GetUserId(); - var existingBook = await _unitOfWork.Books.GetBookByIsbnAsync(addBookDto.ISBN); + var existingBook = await _unitOfWork.Books.GetBookByIsbnAsync(addBookDto.ISBN, ct); if (existingBook is not null) { - if (await _unitOfWork.Books.UserOwnsBookAsync(userId, addBookDto.ISBN)) + if (await _unitOfWork.Books.UserOwnsBookAsync(userId, addBookDto.ISBN, ct)) return BadRequest("You already own this book."); - var userBook = await _unitOfWork.Books.AddUserBookAsync(userId, addBookDto.ISBN, addBookDto.Notes); + var userBook = await _unitOfWork.Books.AddUserBookAsync(userId, addBookDto.ISBN, addBookDto.Notes, ct); - if (await _unitOfWork.CompleteAsync()) + if (await _unitOfWork.CompleteAsync(ct)) { var result = new BookWithOwnerDto { @@ -62,18 +62,18 @@ public async Task> AddBookToCollection(AddBookDto // If book doesn't exist in db, try to fetch from Biblioteka Narodowa API try { - var bookFromApi = await _bibliotekaNarodowaBooksService.GetBookByIsbnAsync(addBookDto.ISBN); + var bookFromApi = await _bibliotekaNarodowaBooksService.GetBookByIsbnAsync(addBookDto.ISBN, ct); if (bookFromApi is null) return NotFound("Book not found in external API, please provide the book details manually."); var newBook = bookFromApi.ToBook(BookSource.BibliotekaNarodowa); - await _unitOfWork.Books.AddBookAsync(newBook); + await _unitOfWork.Books.AddBookAsync(newBook, ct); - var userBook = await _unitOfWork.Books.AddUserBookAsync(userId, addBookDto.ISBN, addBookDto.Notes); + var userBook = await _unitOfWork.Books.AddUserBookAsync(userId, addBookDto.ISBN, addBookDto.Notes, ct); - if (await _unitOfWork.CompleteAsync()) + if (await _unitOfWork.CompleteAsync(ct)) { var result = new BookWithOwnerDto { @@ -101,25 +101,25 @@ public async Task> AddBookToCollection(AddBookDto } [HttpPost("manual")] - public async Task> AddBookManually(AddBookManualDto addBookManualDto) + public async Task> AddBookManually(AddBookManualDto addBookManualDto, CancellationToken ct) { var userId = User.GetUserId(); - if (await _unitOfWork.Books.UserOwnsBookAsync(userId, addBookManualDto.ISBN)) + if (await _unitOfWork.Books.UserOwnsBookAsync(userId, addBookManualDto.ISBN, ct)) return BadRequest("You already own this book."); - var existingBook = await _unitOfWork.Books.GetBookByIsbnAsync(addBookManualDto.ISBN); + var existingBook = await _unitOfWork.Books.GetBookByIsbnAsync(addBookManualDto.ISBN, ct); if (existingBook is null) { var newBook = addBookManualDto.ToBook(BookSource.Users); - await _unitOfWork.Books.AddBookAsync(newBook); + await _unitOfWork.Books.AddBookAsync(newBook, ct); } - var userBook = await _unitOfWork.Books.AddUserBookAsync(userId, addBookManualDto.ISBN, addBookManualDto.Notes); + var userBook = await _unitOfWork.Books.AddUserBookAsync(userId, addBookManualDto.ISBN, addBookManualDto.Notes, ct); - if (await _unitOfWork.CompleteAsync()) + if (await _unitOfWork.CompleteAsync(ct)) { var result = new BookWithOwnerDto { @@ -143,11 +143,11 @@ public async Task> AddBookManually(AddBookManualD } [HttpGet] - public async Task>> GetMyBooks([FromQuery] ElementParams elementParams) + public async Task>> GetMyBooks([FromQuery] ElementParams elementParams, CancellationToken ct) { var userId = User.GetUserId(); - var userBooks = await _unitOfWork.Books.GetUserBooksAsync(userId, elementParams); + var userBooks = await _unitOfWork.Books.GetUserBooksAsync(userId, elementParams, ct); Response.AddPaginationHeader(userBooks.CurrentPage, userBooks.PageSize, userBooks.TotalCount, userBooks.TotalPages); @@ -156,16 +156,17 @@ public async Task>> GetMyBooks([FromQuery] Ele } [HttpGet("friends/{friendId}")] - public async Task>> GetFriendBooks(Guid friendId, [FromQuery] ElementParams elementParams) + public async Task>> GetFriendBooks(Guid friendId, [FromQuery] ElementParams elementParams, + CancellationToken ct) { var userId = User.GetUserId(); - var isFriend = await _unitOfWork.Friendships.AreFriendsAsync(userId, friendId); + var isFriend = await _unitOfWork.Friendships.AreFriendsAsync(userId, friendId, ct); if (!isFriend) return BadRequest("You can only view books of your friends."); - var friendBooks = await _unitOfWork.Books.GetUserBooksAsync(friendId, elementParams); + var friendBooks = await _unitOfWork.Books.GetUserBooksAsync(friendId, elementParams, ct); Response.AddPaginationHeader(friendBooks.CurrentPage, friendBooks.PageSize, friendBooks.TotalCount, friendBooks.TotalPages); @@ -174,11 +175,12 @@ public async Task>> GetFriendBooks(Guid friend } [HttpGet("search-friends")] - public async Task>> SearchBooks([FromQuery] string query, [FromQuery] ElementParams elementParams) + public async Task>> SearchBooks([FromQuery] string query, [FromQuery] ElementParams elementParams, + CancellationToken ct) { var userId = User.GetUserId(); - var books = await _unitOfWork.Books.SearchFriendsBooksAsync(userId, query, elementParams); + var books = await _unitOfWork.Books.SearchFriendsBooksAsync(userId, query, elementParams, ct); Response.AddPaginationHeader(books.CurrentPage, books.PageSize, books.TotalCount, books.TotalPages); diff --git a/API/Controllers/FriendsController.cs b/API/Controllers/FriendsController.cs index eb66542..fa870f3 100644 --- a/API/Controllers/FriendsController.cs +++ b/API/Controllers/FriendsController.cs @@ -20,93 +20,93 @@ public FriendsController(IUnitOfWork unitOfWork) } [HttpPost("request/{friendId}")] - public async Task SendFriendRequest(Guid friendId) + public async Task SendFriendRequest(Guid friendId, CancellationToken ct) { var userId = User.GetUserId(); if (userId == friendId) return BadRequest("Cannot send friend request to yourself"); - var result = await _unitOfWork.Friendships.SendFriendRequestAsync(userId, friendId); + var result = await _unitOfWork.Friendships.SendFriendRequestAsync(userId, friendId, ct); if (!result) return BadRequest("Friend request already exists or user is already a friend"); - await _unitOfWork.CompleteAsync(); + await _unitOfWork.CompleteAsync(ct); return Ok(); } [HttpDelete("request/{friendshipId}/cancel")] - public async Task CancelFriendRequest(Guid friendshipId) + public async Task CancelFriendRequest(Guid friendshipId, CancellationToken ct) { var userId = User.GetUserId(); - var success = await _unitOfWork.Friendships.CancelFriendRequestAsync(userId, friendshipId); + var success = await _unitOfWork.Friendships.CancelFriendRequestAsync(userId, friendshipId, ct); if (!success) return NotFound("Friend request not found or you don't have permission to cancel it"); - if (await _unitOfWork.CompleteAsync()) + if (await _unitOfWork.CompleteAsync(ct)) return NoContent(); return BadRequest("Failed to cancel friend request"); } [HttpPut("accept/{friendshipId}")] - public async Task AcceptFriendRequest(Guid friendshipId) + public async Task AcceptFriendRequest(Guid friendshipId, CancellationToken ct) { var userId = User.GetUserId(); - var friendship = await _unitOfWork.Friendships.GetFriendshipByIdAsync(friendshipId); + var friendship = await _unitOfWork.Friendships.GetFriendshipByIdAsync(friendshipId, ct); if (friendship == null || friendship.ReceiverId != userId) return NotFound(); friendship.Status = FriendshipStatus.Accepted; - await _unitOfWork.CompleteAsync(); + await _unitOfWork.CompleteAsync(ct); return Ok(); } [HttpPut("decline/{friendshipId}")] - public async Task DeclineFriendRequest(Guid friendshipId) + public async Task DeclineFriendRequest(Guid friendshipId, CancellationToken ct) { var userId = User.GetUserId(); - var friendship = await _unitOfWork.Friendships.GetFriendshipByIdAsync(friendshipId); + var friendship = await _unitOfWork.Friendships.GetFriendshipByIdAsync(friendshipId, ct); if (friendship == null || friendship.ReceiverId != userId) return NotFound(); friendship.Status = FriendshipStatus.Declined; - await _unitOfWork.CompleteAsync(); + await _unitOfWork.CompleteAsync(ct); return Ok(); } [HttpDelete("{friendId}")] - public async Task RemoveFriend(Guid friendId) + public async Task RemoveFriend(Guid friendId, CancellationToken ct) { var userId = User.GetUserId(); - var success = await _unitOfWork.Friendships.RemoveFriendAsync(userId, friendId); + var success = await _unitOfWork.Friendships.RemoveFriendAsync(userId, friendId, ct); if (!success) return NotFound("Friendship not found"); - if (await _unitOfWork.CompleteAsync()) + if (await _unitOfWork.CompleteAsync(ct)) return NoContent(); return BadRequest("Failed to remove friend"); } [HttpGet] - public async Task>> GetFriends([FromQuery] ElementParams elementParams) + public async Task>> GetFriends([FromQuery] ElementParams elementParams, CancellationToken ct) { var userId = User.GetUserId(); - var friends = await _unitOfWork.Friendships.GetUserFriendsAsync(userId, elementParams); + var friends = await _unitOfWork.Friendships.GetUserFriendsAsync(userId, elementParams, ct); Response.AddPaginationHeader(friends.CurrentPage, friends.PageSize, friends.TotalCount, friends.TotalPages); @@ -115,11 +115,12 @@ public async Task>> GetFriends([FromQuery] E } [HttpGet("requests")] - public async Task>> GetPendingRequests([FromQuery] ElementParams elementParams) + public async Task>> GetPendingRequests([FromQuery] ElementParams elementParams, + CancellationToken ct) { var userId = User.GetUserId(); - var requests = await _unitOfWork.Friendships.GetPendingRequestsAsync(userId, elementParams); + var requests = await _unitOfWork.Friendships.GetPendingRequestsAsync(userId, elementParams, ct); Response.AddPaginationHeader(requests.CurrentPage, requests.PageSize, requests.TotalCount, requests.TotalPages); diff --git a/API/Controllers/LoansController.cs b/API/Controllers/LoansController.cs index 87287fd..d91fd51 100644 --- a/API/Controllers/LoansController.cs +++ b/API/Controllers/LoansController.cs @@ -21,14 +21,14 @@ public LoansController(IUnitOfWork unitOfWork) } [HttpPost] - public async Task RequestLoan(BorrowRequestDto borrowRequestDto) + public async Task RequestLoan(BorrowRequestDto borrowRequestDto, CancellationToken ct) { - var userBook = await _unitOfWork.Books.GetUserBookByIdAndUserIdAsync(borrowRequestDto.ISBN, borrowRequestDto.OwnerId); + var userBook = await _unitOfWork.Books.GetUserBookByIdAndUserIdAsync(borrowRequestDto.ISBN, borrowRequestDto.OwnerId, ct); - if(await _unitOfWork.Loans.IsBookAvailableForLoanAsync(borrowRequestDto.OwnerId, borrowRequestDto.ISBN) is false) + if(await _unitOfWork.Loans.IsBookAvailableForLoanAsync(borrowRequestDto.OwnerId, borrowRequestDto.ISBN, ct) is false) return BadRequest("This book is currently not available for loan."); - if(await _unitOfWork.Loans.HasPendingLoanAsync(borrowRequestDto.OwnerId, borrowRequestDto.ISBN, User.GetUserId())) + if(await _unitOfWork.Loans.HasPendingLoanAsync(borrowRequestDto.OwnerId, borrowRequestDto.ISBN, User.GetUserId(), ct)) return BadRequest("You already have a pending loan request for this book."); var newLoan = new Loan @@ -42,17 +42,17 @@ public async Task RequestLoan(BorrowRequestDto borrowRequestDto) UserBookId = userBook.Id }; - await _unitOfWork.Loans.AddLoanAsync(newLoan); + await _unitOfWork.Loans.AddLoanAsync(newLoan, ct); - if(await _unitOfWork.CompleteAsync()) return Ok(); + if(await _unitOfWork.CompleteAsync(ct)) return Ok(); return BadRequest("Failed to request loan"); } [HttpPost("respond/{loanId}")] - public async Task RespondToLoan(Guid loanId, ResponseLoanDto respondToLoanDto) + public async Task RespondToLoan(Guid loanId, ResponseLoanDto respondToLoanDto, CancellationToken ct) { - var loan = await _unitOfWork.Loans.GetLoanByIdAsync(loanId); + var loan = await _unitOfWork.Loans.GetLoanByIdAsync(loanId, ct); if (loan == null) return NotFound("Loan request not found"); if (loan.OwnerId != User.GetUserId()) return Unauthorized("You are not authorized to respond to this loan request"); @@ -66,15 +66,15 @@ public async Task RespondToLoan(Guid loanId, ResponseLoanDto respo loan.Notes = respondToLoanDto.Notes; } - if(await _unitOfWork.CompleteAsync()) return Ok(); + if(await _unitOfWork.CompleteAsync(ct)) return Ok(); return BadRequest("Failed to respond to loan request"); } [HttpPost("loan/{loanId}")] - public async Task LoanBook(Guid loanId) + public async Task LoanBook(Guid loanId, CancellationToken ct) { - var loan = await _unitOfWork.Loans.GetLoanByIdAsync(loanId); + var loan = await _unitOfWork.Loans.GetLoanByIdAsync(loanId, ct); if (loan == null) return NotFound("Loan request not found"); if (loan.OwnerId != User.GetUserId() && loan.BorrowerId != User.GetUserId()) return Unauthorized("You are not authorized to respond to this loan request"); @@ -82,18 +82,18 @@ public async Task LoanBook(Guid loanId) loan.Status = LoanStatus.Active; loan.LoanDate = DateTime.UtcNow; - var userBook = await _unitOfWork.Books.GetUserBookByIdAndUserIdAsync(loan.ISBN, loan.OwnerId); + var userBook = await _unitOfWork.Books.GetUserBookByIdAndUserIdAsync(loan.ISBN, loan.OwnerId, ct); if (userBook != null) userBook.IsAvailable = false; - if(await _unitOfWork.CompleteAsync()) return Ok(); + if(await _unitOfWork.CompleteAsync(ct)) return Ok(); return BadRequest("Failed to loan book"); } [HttpPost("return/{loanId}")] - public async Task ReturnLoan(Guid loanId) + public async Task ReturnLoan(Guid loanId, CancellationToken ct) { - var loan = await _unitOfWork.Loans.GetLoanByIdAsync(loanId); + var loan = await _unitOfWork.Loans.GetLoanByIdAsync(loanId, ct); if (loan == null) return NotFound("Loan not found"); if (loan.BorrowerId != User.GetUserId()) return Unauthorized("You are not authorized to return this loan"); @@ -104,15 +104,15 @@ public async Task ReturnLoan(Guid loanId) loan.Status = LoanStatus.Returned; loan.ReturnedAt = DateTime.UtcNow; - if(await _unitOfWork.CompleteAsync()) return Ok(); + if(await _unitOfWork.CompleteAsync(ct)) return Ok(); return BadRequest("Failed to return loan"); } [HttpGet] - public async Task>> GetLoans([FromQuery] ElementParams elementParams) + public async Task>> GetLoans([FromQuery] ElementParams elementParams, CancellationToken ct) { - var loans = await _unitOfWork.Loans.GetActiveLoansAsync(User.GetUserId(), elementParams); + var loans = await _unitOfWork.Loans.GetActiveLoansAsync(User.GetUserId(), elementParams, ct); Response.AddPaginationHeader(loans.CurrentPage, loans.PageSize, loans.TotalCount, loans.TotalPages); @@ -121,9 +121,9 @@ public async Task>> GetLoans([FromQuery] Eleme } [HttpGet("borrowed")] - public async Task>> GetBorrowedLoans([FromQuery] ElementParams elementParams) + public async Task>> GetBorrowedLoans([FromQuery] ElementParams elementParams, CancellationToken ct) { - var borrowedLoans = await _unitOfWork.Loans.GetLoansForBorrowerAsync(User.GetUserId(), elementParams); + var borrowedLoans = await _unitOfWork.Loans.GetLoansForBorrowerAsync(User.GetUserId(), elementParams, ct); Response.AddPaginationHeader(borrowedLoans.CurrentPage, borrowedLoans.PageSize, borrowedLoans.TotalCount, borrowedLoans.TotalPages); @@ -132,9 +132,9 @@ public async Task>> GetBorrowedLoans([FromQuer } [HttpGet("lent")] - public async Task>> GetLentLoans([FromQuery] ElementParams elementParams) + public async Task>> GetLentLoans([FromQuery] ElementParams elementParams, CancellationToken ct) { - var lentLoans = await _unitOfWork.Loans.GetLoansForOwnerAsync(User.GetUserId(), elementParams); + var lentLoans = await _unitOfWork.Loans.GetLoansForOwnerAsync(User.GetUserId(), elementParams, ct); Response.AddPaginationHeader(lentLoans.CurrentPage, lentLoans.PageSize, lentLoans.TotalCount, lentLoans.TotalPages); @@ -143,9 +143,9 @@ public async Task>> GetLentLoans([FromQuery] E } [HttpGet("history")] - public async Task>> GetLoanHistory([FromQuery] ElementParams elementParams) + public async Task>> GetLoanHistory([FromQuery] ElementParams elementParams, CancellationToken ct) { - var loanHistory = await _unitOfWork.Loans.GetLoanHistoryAsync(User.GetUserId(), elementParams); + var loanHistory = await _unitOfWork.Loans.GetLoanHistoryAsync(User.GetUserId(), elementParams, ct); Response.AddPaginationHeader(loanHistory.CurrentPage, loanHistory.PageSize, loanHistory.TotalCount, loanHistory.TotalPages); @@ -154,9 +154,9 @@ public async Task>> GetLoanHistory([FromQuery] } [HttpGet("pending-requests")] - public async Task>> GetPendingRequests([FromQuery] ElementParams elementParams) + public async Task>> GetPendingRequests([FromQuery] ElementParams elementParams, CancellationToken ct) { - var pendingRequests = await _unitOfWork.Loans.GetPendingRequestsForOwnerAsync(User.GetUserId(), elementParams); + var pendingRequests = await _unitOfWork.Loans.GetPendingRequestsForOwnerAsync(User.GetUserId(), elementParams, ct); Response.AddPaginationHeader(pendingRequests.CurrentPage, pendingRequests.PageSize, pendingRequests.TotalCount, pendingRequests.TotalPages); @@ -165,9 +165,9 @@ public async Task>> GetPendingRequests([FromQu } [HttpGet("pending-requests/borrower")] - public async Task>> GetPendingRequestsFromBorrower([FromQuery] ElementParams elementParams) + public async Task>> GetPendingRequestsFromBorrower([FromQuery] ElementParams elementParams, CancellationToken ct) { - var pendingRequests = await _unitOfWork.Loans.GetPendingRequestsFromBorrowerAsync(User.GetUserId(), elementParams); + var pendingRequests = await _unitOfWork.Loans.GetPendingRequestsFromBorrowerAsync(User.GetUserId(), elementParams, ct); Response.AddPaginationHeader(pendingRequests.CurrentPage, pendingRequests.PageSize, pendingRequests.TotalCount, pendingRequests.TotalPages); diff --git a/API/Controllers/UsersController.cs b/API/Controllers/UsersController.cs index 3812d7c..9e26984 100644 --- a/API/Controllers/UsersController.cs +++ b/API/Controllers/UsersController.cs @@ -18,11 +18,12 @@ public UsersController(IUnitOfWork unitOfWork) [Authorize] [HttpGet("search")] - public async Task>> SearchUsers([FromQuery] string query, [FromQuery] ElementParams elementParams) + public async Task>> SearchUsers([FromQuery] string query, [FromQuery] ElementParams elementParams, + CancellationToken ct) { var currentUserId = User.GetUserId(); - var users = await _unitOfWork.Users.SearchUsersAsync(currentUserId, query, elementParams); + var users = await _unitOfWork.Users.SearchUsersAsync(currentUserId, query, elementParams, ct); Response.AddPaginationHeader(users.CurrentPage, users.PageSize, users.TotalCount, users.TotalPages); diff --git a/API/Data/BookRepository.cs b/API/Data/BookRepository.cs index a79653b..9327fe4 100644 --- a/API/Data/BookRepository.cs +++ b/API/Data/BookRepository.cs @@ -15,23 +15,23 @@ public BookRepository(DataContext context) _context = context; } - public async Task GetBookByIsbnAsync(string isbn) + public async Task GetBookByIsbnAsync(string isbn, CancellationToken ct) { - return await _context.Books.FindAsync(isbn); + return await _context.Books.FindAsync(isbn, ct); } - public async Task GetUserBookByIdAndUserIdAsync(string isbn, Guid userId) + public async Task GetUserBookByIdAndUserIdAsync(string isbn, Guid userId, CancellationToken ct) { return await _context.UserBooks - .FirstOrDefaultAsync(ub => ub.ISBN == isbn && ub.UserId == userId); + .FirstOrDefaultAsync(ub => ub.ISBN == isbn && ub.UserId == userId, ct); } - public async Task AddBookAsync(Book book) + public async Task AddBookAsync(Book book, CancellationToken ct) { - await _context.Books.AddAsync(book); + await _context.Books.AddAsync(book, ct); } - public async Task AddUserBookAsync(Guid userId, string isbn, string? notes) + public async Task AddUserBookAsync(Guid userId, string isbn, string? notes, CancellationToken ct) { var userBook = new UserBook { @@ -43,37 +43,38 @@ public async Task AddUserBookAsync(Guid userId, string isbn, string? n Notes = notes }; - await _context.UserBooks.AddAsync(userBook); + await _context.UserBooks.AddAsync(userBook, ct); return userBook; } - public async Task UserOwnsBookAsync(Guid userId, string isbn) + public async Task UserOwnsBookAsync(Guid userId, string isbn, CancellationToken ct) { return await _context.UserBooks - .AnyAsync(ub => ub.UserId == userId && ub.ISBN == isbn); + .AnyAsync(ub => ub.UserId == userId && ub.ISBN == isbn, ct); } - public async Task> GetUserBooksAsync(Guid userId, ElementParams elementParams) + public async Task> GetUserBooksAsync(Guid userId, ElementParams elementParams, CancellationToken ct) { var books = _context.UserBooks .Where(ub => ub.UserId == userId) .Include(ub => ub.Book); - return await PagedList.CreateAsync(books, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(books, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task> SearchFriendsBooksAsync(Guid userId, string query, ElementParams elementParams) + public async Task> SearchFriendsBooksAsync(Guid userId, string query, ElementParams elementParams, + CancellationToken ct) { var friendIds = await _context.Friendships .Where(f => f.RequesterId == userId || f.ReceiverId == userId) .Select(f => f.RequesterId == userId ? f.ReceiverId : f.RequesterId) - .ToListAsync(); + .ToListAsync(ct); var books = _context.UserBooks .Where(ub => friendIds.Contains(ub.UserId) && ub.Book.Title.ToLower().Contains(query.ToLower())) .Include(ub => ub.Book); - return await PagedList.CreateAsync(books, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(books, elementParams.PageNumber, elementParams.PageSize, ct); } } \ No newline at end of file diff --git a/API/Data/FriendshipRepository.cs b/API/Data/FriendshipRepository.cs index 44f319d..5e4e90d 100644 --- a/API/Data/FriendshipRepository.cs +++ b/API/Data/FriendshipRepository.cs @@ -16,21 +16,21 @@ public FriendshipRepository(DataContext context) _context = context; } - public async Task AreFriendsAsync(Guid userId, Guid friendId) + public async Task AreFriendsAsync(Guid userId, Guid friendId, CancellationToken ct) { return await _context.Friendships.AnyAsync(f => ((f.RequesterId == userId && f.ReceiverId == friendId) || (f.RequesterId == friendId && f.ReceiverId == userId)) && - f.Status == FriendshipStatus.Accepted); + f.Status == FriendshipStatus.Accepted, ct); } - public async Task CancelFriendRequestAsync(Guid userId, Guid friendshipId) + public async Task CancelFriendRequestAsync(Guid userId, Guid friendshipId, CancellationToken ct) { var friendship = await _context.Friendships .FirstOrDefaultAsync(f => f.Id == friendshipId && f.RequesterId == userId && - f.Status == FriendshipStatus.Pending); + f.Status == FriendshipStatus.Pending, ct); if (friendship == null) return false; @@ -39,37 +39,37 @@ public async Task CancelFriendRequestAsync(Guid userId, Guid friendshipId) return true; } - public async Task GetFriendshipByIdAsync(Guid friendshipId) + public async Task GetFriendshipByIdAsync(Guid friendshipId, CancellationToken ct) { - return await _context.Friendships.FindAsync(friendshipId); + return await _context.Friendships.FindAsync(friendshipId, ct); } - public async Task> GetPendingRequestsAsync(Guid userId, ElementParams elementParams) + public async Task> GetPendingRequestsAsync(Guid userId, ElementParams elementParams, CancellationToken ct) { var friendRequests = _context.Friendships .Include(fr => fr.Requester) .Where(fr => fr.ReceiverId == userId && fr.Status == FriendshipStatus.Pending); - return await PagedList.CreateAsync(friendRequests, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(friendRequests, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task> GetUserFriendsAsync(Guid userId, ElementParams elementParams) + public async Task> GetUserFriendsAsync(Guid userId, ElementParams elementParams, CancellationToken ct) { var friends = _context.Friendships .Include(f => f.Requester) .Include(f => f.Receiver) .Where(f => (f.RequesterId == userId || f.ReceiverId == userId) && f.Status == FriendshipStatus.Accepted); - return await PagedList.CreateAsync(friends, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(friends, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task RemoveFriendAsync(Guid userId, Guid friendId) + public async Task RemoveFriendAsync(Guid userId, Guid friendId, CancellationToken ct) { var friendship = await _context.Friendships .FirstOrDefaultAsync(f => ((f.RequesterId == userId && f.ReceiverId == friendId) || (f.RequesterId == friendId && f.ReceiverId == userId)) && - f.Status == FriendshipStatus.Accepted); + f.Status == FriendshipStatus.Accepted, ct); if (friendship == null) return false; @@ -78,11 +78,11 @@ public async Task RemoveFriendAsync(Guid userId, Guid friendId) return true; } - public async Task SendFriendRequestAsync(Guid userId, Guid friendId) + public async Task SendFriendRequestAsync(Guid userId, Guid friendId, CancellationToken ct) { if (await _context.Friendships.AnyAsync(f => (f.RequesterId == userId && f.ReceiverId == friendId) || - (f.RequesterId == friendId && f.ReceiverId == userId))) + (f.RequesterId == friendId && f.ReceiverId == userId), ct)) { return false; // Already friends or request exists } diff --git a/API/Data/LoanRepository.cs b/API/Data/LoanRepository.cs index 770b06b..ba40701 100644 --- a/API/Data/LoanRepository.cs +++ b/API/Data/LoanRepository.cs @@ -16,12 +16,12 @@ public LoanRepository(DataContext context) _context = context; } - public async Task AddLoanAsync(Loan loan) + public async Task AddLoanAsync(Loan loan, CancellationToken ct) { - await _context.Loans.AddAsync(loan); + await _context.Loans.AddAsync(loan, ct); } - public async Task> GetActiveLoansAsync(Guid userId, ElementParams elementParams) + public async Task> GetActiveLoansAsync(Guid userId, ElementParams elementParams, CancellationToken ct) { var loans = _context.Loans .Where(l => l.BorrowerId == userId && (l.Status == LoanStatus.Active || l.Status == LoanStatus.Overdue)) @@ -29,15 +29,15 @@ public async Task> GetActiveLoansAsync(Guid userId, ElementParam .Include(l => l.Owner) .Include(l => l.Borrower); - return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task GetLoanByIdAsync(Guid id) + public async Task GetLoanByIdAsync(Guid id, CancellationToken ct) { - return await _context.Loans.FindAsync(id); + return await _context.Loans.FindAsync(id, ct); } - public async Task> GetLoanHistoryAsync(Guid userId, ElementParams elementParams) + public async Task> GetLoanHistoryAsync(Guid userId, ElementParams elementParams, CancellationToken ct) { var loans = _context.Loans .Where(l => (l.BorrowerId == userId || l.OwnerId == userId) && @@ -46,10 +46,11 @@ public async Task> GetLoanHistoryAsync(Guid userId, ElementParam .Include(l => l.Owner) .Include(l => l.Borrower); - return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task> GetLoansForBorrowerAsync(Guid borrowerId, ElementParams elementParams, LoanStatus? status = null) + public async Task> GetLoansForBorrowerAsync(Guid borrowerId, ElementParams elementParams, + CancellationToken ct, LoanStatus? status = null) { var query = _context.Loans .Where(l => l.BorrowerId == borrowerId); @@ -62,10 +63,11 @@ public async Task> GetLoansForBorrowerAsync(Guid borrowerId, Ele .Include(l => l.Owner) .Include(l => l.Borrower); - return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task> GetLoansForOwnerAsync(Guid ownerId, ElementParams elementParams, LoanStatus? status = null) + public async Task> GetLoansForOwnerAsync(Guid ownerId, ElementParams elementParams, + CancellationToken ct, LoanStatus? status = null) { var query = _context.Loans .Where(l => l.OwnerId == ownerId); @@ -78,10 +80,11 @@ public async Task> GetLoansForOwnerAsync(Guid ownerId, ElementPa .Include(l => l.Owner) .Include(l => l.Borrower); - return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task> GetPendingRequestsForOwnerAsync(Guid ownerId, ElementParams elementParams) + public async Task> GetPendingRequestsForOwnerAsync(Guid ownerId, ElementParams elementParams, + CancellationToken ct) { var loans = _context.Loans .Where(l => l.OwnerId == ownerId && l.Status == LoanStatus.Pending) @@ -89,10 +92,11 @@ public async Task> GetPendingRequestsForOwnerAsync(Guid ownerId, .Include(l => l.Owner) .Include(l => l.Borrower); - return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task> GetPendingRequestsFromBorrowerAsync(Guid borrowerId, ElementParams elementParams) + public async Task> GetPendingRequestsFromBorrowerAsync(Guid borrowerId, ElementParams elementParams, + CancellationToken ct) { var loans = _context.Loans .Where(l => l.BorrowerId == borrowerId && l.Status == LoanStatus.Pending) @@ -100,21 +104,21 @@ public async Task> GetPendingRequestsFromBorrowerAsync(Guid borr .Include(l => l.Owner) .Include(l => l.Borrower); - return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(loans, elementParams.PageNumber, elementParams.PageSize, ct); } - public async Task HasPendingLoanAsync(Guid ownerId, string isbn, Guid borrowerId) + public async Task HasPendingLoanAsync(Guid ownerId, string isbn, Guid borrowerId, CancellationToken ct) { return await _context.UserBooks .Where(ub => ub.UserId == ownerId && ub.Book.ISBN == isbn) .SelectMany(ub => ub.Loans) - .AnyAsync(l => l.BorrowerId == borrowerId && l.Status == LoanStatus.Pending); + .AnyAsync(l => l.BorrowerId == borrowerId && l.Status == LoanStatus.Pending, ct); } - public async Task IsBookAvailableForLoanAsync(Guid ownerId, string isbn) + public async Task IsBookAvailableForLoanAsync(Guid ownerId, string isbn, CancellationToken ct) { return await _context.UserBooks .Where(ub => ub.UserId == ownerId && ub.Book.ISBN == isbn) - .AnyAsync(b => b.IsAvailable); + .AnyAsync(b => b.IsAvailable, ct); } } \ No newline at end of file diff --git a/API/Data/UnitOfWork.cs b/API/Data/UnitOfWork.cs index c801ed5..1b15aed 100644 --- a/API/Data/UnitOfWork.cs +++ b/API/Data/UnitOfWork.cs @@ -16,5 +16,5 @@ public UnitOfWork(DataContext context) public IFriendshipRepository Friendships => new FriendshipRepository(_context); public ILoanRepository Loans => new LoanRepository(_context); - public async Task CompleteAsync() => await _context.SaveChangesAsync() > 0; + public async Task CompleteAsync(CancellationToken ct) => await _context.SaveChangesAsync(ct) > 0; } \ No newline at end of file diff --git a/API/Data/UserRepository.cs b/API/Data/UserRepository.cs index b31bb63..588b448 100644 --- a/API/Data/UserRepository.cs +++ b/API/Data/UserRepository.cs @@ -15,29 +15,30 @@ public UserRepository(DataContext context) _context = context; } - public async Task GetUserByEmailAsync(string email) + public async Task GetUserByEmailAsync(string email, CancellationToken ct) { return await _context.Users - .FirstOrDefaultAsync(u => u.Email == email.ToLower()); + .FirstOrDefaultAsync(u => u.Email == email.ToLower(), ct); } - public async Task GetUserByIdAsync(Guid id) + public async Task GetUserByIdAsync(Guid id, CancellationToken ct) { return await _context.Users .Include(u => u.Books) .ThenInclude(ub => ub.Book) .Include(u => u.SentFriendRequests) .Include(u => u.ReceivedFriendRequests) - .FirstOrDefaultAsync(u => u.Id == id); + .FirstOrDefaultAsync(u => u.Id == id, ct); } - public async Task GetUserByUsernameAsync(string username) + public async Task GetUserByUsernameAsync(string username, CancellationToken ct) { return await _context.Users - .FirstOrDefaultAsync(u => u.UserName == username.ToLower()); + .FirstOrDefaultAsync(u => u.UserName == username.ToLower(), ct); } - public async Task> SearchUsersAsync(Guid currentUserId, string query, ElementParams elementParams) + public async Task> SearchUsersAsync(Guid currentUserId, string query, ElementParams elementParams, + CancellationToken ct) { var users = _context.Users .Where(u => u.Id != currentUserId && @@ -57,6 +58,6 @@ public async Task> SearchUsersAsync(Guid currentUserId, CreatedAt = u.CreatedAt }); - return await PagedList.CreateAsync(users, elementParams.PageNumber, elementParams.PageSize); + return await PagedList.CreateAsync(users, elementParams.PageNumber, elementParams.PageSize, ct); } } \ No newline at end of file diff --git a/API/Helpers/PagedList.cs b/API/Helpers/PagedList.cs index 41180de..fbccb07 100644 --- a/API/Helpers/PagedList.cs +++ b/API/Helpers/PagedList.cs @@ -20,10 +20,10 @@ public PagedList(IEnumerable items, int count, int pageNumber, int pageSize) public int PageSize { get; set; } public int TotalCount { get; set; } - public static async Task> CreateAsync(IQueryable source, int pageNumber, int pageSize) + public static async Task> CreateAsync(IQueryable source, int pageNumber, int pageSize, CancellationToken ct) { - var count = await source.CountAsync(); - var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync(); + var count = await source.CountAsync(ct); + var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync(ct); return new PagedList(items, count, pageNumber, pageSize); } } \ No newline at end of file diff --git a/API/Interfaces/IBibliotekaNarodowaBooksService.cs b/API/Interfaces/IBibliotekaNarodowaBooksService.cs index 49cd824..3d18aa1 100644 --- a/API/Interfaces/IBibliotekaNarodowaBooksService.cs +++ b/API/Interfaces/IBibliotekaNarodowaBooksService.cs @@ -4,5 +4,5 @@ namespace API.Interfaces; public interface IBibliotekaNarodowaBooksService { - Task GetBookByIsbnAsync(string isbn); + Task GetBookByIsbnAsync(string isbn, CancellationToken ct); } \ No newline at end of file diff --git a/API/Interfaces/IBookRepository.cs b/API/Interfaces/IBookRepository.cs index f4b6c28..6ac2c8f 100644 --- a/API/Interfaces/IBookRepository.cs +++ b/API/Interfaces/IBookRepository.cs @@ -6,11 +6,11 @@ namespace API.Interfaces; public interface IBookRepository { - Task GetBookByIsbnAsync(string isbn); - Task GetUserBookByIdAndUserIdAsync(string isbn, Guid userId); - Task UserOwnsBookAsync(Guid userId, string isbn); - Task AddBookAsync(Book book); - Task AddUserBookAsync(Guid userId, string isbn, string? notes); - Task> GetUserBooksAsync(Guid userId, ElementParams elementParams); - Task> SearchFriendsBooksAsync(Guid userId, string query, ElementParams elementParams); + Task GetBookByIsbnAsync(string isbn, CancellationToken ct); + Task GetUserBookByIdAndUserIdAsync(string isbn, Guid userId, CancellationToken ct); + Task UserOwnsBookAsync(Guid userId, string isbn, CancellationToken ct); + Task AddBookAsync(Book book, CancellationToken ct); + Task AddUserBookAsync(Guid userId, string isbn, string? notes, CancellationToken ct); + Task> GetUserBooksAsync(Guid userId, ElementParams elementParams, CancellationToken ct); + Task> SearchFriendsBooksAsync(Guid userId, string query, ElementParams elementParams, CancellationToken ct); } \ No newline at end of file diff --git a/API/Interfaces/IFriendshipRepository.cs b/API/Interfaces/IFriendshipRepository.cs index 9baea8e..b979d96 100644 --- a/API/Interfaces/IFriendshipRepository.cs +++ b/API/Interfaces/IFriendshipRepository.cs @@ -6,11 +6,11 @@ namespace API.Interfaces; public interface IFriendshipRepository { - Task SendFriendRequestAsync(Guid userId, Guid friendId); - Task GetFriendshipByIdAsync(Guid friendshipId); - Task> GetUserFriendsAsync(Guid userId, ElementParams elementParams); - Task> GetPendingRequestsAsync(Guid userId, ElementParams elementParams); - Task RemoveFriendAsync(Guid userId, Guid friendId); - Task CancelFriendRequestAsync(Guid userId, Guid friendshipId); - Task AreFriendsAsync(Guid userId, Guid friendId); + Task SendFriendRequestAsync(Guid userId, Guid friendId, CancellationToken ct); + Task GetFriendshipByIdAsync(Guid friendshipId, CancellationToken ct); + Task> GetUserFriendsAsync(Guid userId, ElementParams elementParams, CancellationToken ct); + Task> GetPendingRequestsAsync(Guid userId, ElementParams elementParams, CancellationToken ct); + Task RemoveFriendAsync(Guid userId, Guid friendId, CancellationToken ct); + Task CancelFriendRequestAsync(Guid userId, Guid friendshipId, CancellationToken ct); + Task AreFriendsAsync(Guid userId, Guid friendId, CancellationToken ct); } \ No newline at end of file diff --git a/API/Interfaces/ILoanRepository.cs b/API/Interfaces/ILoanRepository.cs index d70357d..6fd054a 100644 --- a/API/Interfaces/ILoanRepository.cs +++ b/API/Interfaces/ILoanRepository.cs @@ -7,19 +7,19 @@ namespace API.Interfaces; public interface ILoanRepository { - Task GetLoanByIdAsync(Guid id); - Task AddLoanAsync(Loan loan); + Task GetLoanByIdAsync(Guid id, CancellationToken ct); + Task AddLoanAsync(Loan loan, CancellationToken ct); - Task> GetLoansForOwnerAsync(Guid ownerId, ElementParams elementParams, LoanStatus? status = null); - Task> GetPendingRequestsForOwnerAsync(Guid ownerId, ElementParams elementParams); + Task> GetLoansForOwnerAsync(Guid ownerId, ElementParams elementParams, CancellationToken ct, LoanStatus? status = null); + Task> GetPendingRequestsForOwnerAsync(Guid ownerId, ElementParams elementParams, CancellationToken ct); - Task> GetLoansForBorrowerAsync(Guid borrowerId, ElementParams elementParams, LoanStatus? status = null); - Task> GetPendingRequestsFromBorrowerAsync(Guid borrowerId, ElementParams elementParams); + Task> GetLoansForBorrowerAsync(Guid borrowerId, ElementParams elementParams, CancellationToken ct, LoanStatus? status = null); + Task> GetPendingRequestsFromBorrowerAsync(Guid borrowerId, ElementParams elementParams, CancellationToken ct); - Task> GetActiveLoansAsync(Guid userId, ElementParams elementParams); + Task> GetActiveLoansAsync(Guid userId, ElementParams elementParams, CancellationToken ct); - Task> GetLoanHistoryAsync(Guid userId, ElementParams elementParams); + Task> GetLoanHistoryAsync(Guid userId, ElementParams elementParams, CancellationToken ct); - Task IsBookAvailableForLoanAsync(Guid ownerId, string isbn); - Task HasPendingLoanAsync(Guid ownerId, string isbn, Guid borrowerId); + Task IsBookAvailableForLoanAsync(Guid ownerId, string isbn, CancellationToken ct); + Task HasPendingLoanAsync(Guid ownerId, string isbn, Guid borrowerId, CancellationToken ct); } \ No newline at end of file diff --git a/API/Interfaces/IUnitOfWork.cs b/API/Interfaces/IUnitOfWork.cs index 002622d..0ad771f 100644 --- a/API/Interfaces/IUnitOfWork.cs +++ b/API/Interfaces/IUnitOfWork.cs @@ -7,5 +7,5 @@ public interface IUnitOfWork IFriendshipRepository Friendships { get; } ILoanRepository Loans { get; } - Task CompleteAsync(); + Task CompleteAsync(CancellationToken ct); } \ No newline at end of file diff --git a/API/Interfaces/IUserRepository.cs b/API/Interfaces/IUserRepository.cs index 6a36847..5034db6 100644 --- a/API/Interfaces/IUserRepository.cs +++ b/API/Interfaces/IUserRepository.cs @@ -6,11 +6,11 @@ namespace API.Interfaces; public interface IUserRepository { - Task GetUserByIdAsync(Guid id); - Task GetUserByEmailAsync(string email); - Task GetUserByUsernameAsync(string username); + Task GetUserByIdAsync(Guid id, CancellationToken ct); + Task GetUserByEmailAsync(string email, CancellationToken ct); + Task GetUserByUsernameAsync(string username, CancellationToken ct); - Task> SearchUsersAsync(Guid currentUserId, string query, ElementParams elementParams); + Task> SearchUsersAsync(Guid currentUserId, string query, ElementParams elementParams, CancellationToken ct); //Task GetUserProfileAsync(Guid userId, Guid currentUserId); diff --git a/API/Services/BibliotekaNarodowaBooksService.cs b/API/Services/BibliotekaNarodowaBooksService.cs index 1435feb..4490e91 100644 --- a/API/Services/BibliotekaNarodowaBooksService.cs +++ b/API/Services/BibliotekaNarodowaBooksService.cs @@ -16,11 +16,11 @@ public BibliotekaNarodowaBooksService(HttpClient httpClient, ILogger GetBookByIsbnAsync(string isbn) + public async Task GetBookByIsbnAsync(string isbn, CancellationToken ct) { try { - var response = await _httpClient.GetAsync($"bibs.json?isbnIssn={isbn}"); + var response = await _httpClient.GetAsync($"bibs.json?isbnIssn={isbn}", ct); if (!response.IsSuccessStatusCode) { @@ -29,7 +29,7 @@ public BibliotekaNarodowaBooksService(HttpClient httpClient, ILogger role.Contains(indicator)); + } } \ No newline at end of file