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

Achat de cartes depuis la marketplace avec vérifications pré-condition #13

Merged
merged 1 commit into from
Jun 2, 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

import cpe.atelier3.auth.domain.auth.AuthenticationService;
import cpe.atelier3.auth.domain.user.UserService;
import cpe.atelier3.commons.card.Card;
import cpe.atelier3.commons.card.exception.CardNotFoundException;
import cpe.atelier3.commons.user.User;
import cpe.atelier3.commons.user.dto.*;
import cpe.atelier3.commons.user.exception.InvalidTokenException;
import cpe.atelier3.commons.user.exception.UserNotFoundException;
import cpe.atelier3.commons.user.exception.*;
import org.springframework.web.bind.annotation.*;

import java.net.URISyntaxException;
import java.util.List;
import java.util.Objects;


@RestController
Expand All @@ -20,10 +24,13 @@ public class UserController {

private final AuthenticationService authenticationService;

public UserController(UserDtoMapper userDtoMapper, UserService userService, AuthenticationService authenticationService) {
private final UserPaymentRequestDtoMapper userPaymentRequestDtoMapper;

public UserController(UserDtoMapper userDtoMapper, UserService userService, AuthenticationService authenticationService, UserPaymentRequestDtoMapper userPaymentRequestDtoMapper) {
this.userDtoMapper = userDtoMapper;
this.userService = userService;
this.authenticationService = authenticationService;
this.userPaymentRequestDtoMapper = userPaymentRequestDtoMapper;
}

@GetMapping("/all")
Expand All @@ -50,4 +57,33 @@ public PublicUserDTO findPublicUserById(@CookieValue("token") String token, @Pat
authenticationService.checkAuthentication(token);
return userDtoMapper.userToPublicUserDto(userService.findUserById(id));
}

@PostMapping("/private/payment")
public void processPayment(@CookieValue("token") String token, @RequestBody UserPaymentRequestDTO paymentRequestDto) throws InvalidTokenException,
UserNotFoundException, UserSelfPaymentException, UserPaymentInsufficientBalanceException, UserPaymentImpersonationException {
String uid = authenticationService.checkAuthentication(token);
if (! uid.equals(paymentRequestDto.buyerId().toString())) {
throw new UserPaymentImpersonationException();
}
userService.processPayment(userPaymentRequestDtoMapper.userPaymentRequestDtoToUserPaymentRequest(paymentRequestDto));
}

@DeleteMapping("/{uid:[0-9]+}/card/{cid:[0-9]+}")
public void deleteCardOfUser(@CookieValue("service_token") String serviceToken, @PathVariable String uid, @PathVariable String cid) throws UserNotFoundException {
authenticationService.checkServiceToken(serviceToken);
userService.removeCard(Long.valueOf(uid), Long.valueOf(cid));
}

@PutMapping("/{uid:[0-9]+}/card/{cid:[0-9]+}")
public void addCardToUser(@CookieValue("service_token") String serviceToken, @PathVariable String uid, @PathVariable String cid) throws UserNotFoundException,
URISyntaxException, CardNotFoundException {
authenticationService.checkServiceToken(serviceToken);
userService.addCard(Long.valueOf(uid), Long.valueOf(cid));
}

@GetMapping("/{uid:[0-9]+}/card/{cid:[0-9]+}")
public void getCardOfUser(@CookieValue("service_token") String serviceToken, @PathVariable String uid, @PathVariable String cid) throws CardNotOwnedException, UserNotFoundException {
authenticationService.checkServiceToken(serviceToken);
userService.getCardFromUser(Long.valueOf(uid), Long.valueOf(cid));
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
package cpe.atelier3.auth.domain.auth;

import cpe.atelier3.auth.domain.auth.jwt.JWTGenerator;
import cpe.atelier3.auth.domain.user.IUserRepository;
import cpe.atelier3.commons.user.exception.InvalidTokenException;
import cpe.atelier3.commons.user.User;
import cpe.atelier3.commons.user.exception.IncorrectPasswordException;
import cpe.atelier3.commons.user.exception.InvalidTokenException;
import cpe.atelier3.commons.user.exception.UserDoesNotExistException;
import cpe.atelier3.auth.domain.auth.jwt.JWTGenerator;
import cpe.atelier3.commons.user.User;
import cpe.atelier3.auth.repository.user.UserRepository;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import jakarta.servlet.http.Cookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.Optional;
import org.springframework.web.server.ResponseStatusException;

import java.util.Optional;

import static cpe.atelier3.auth.domain.auth.jwt.JWTGenerator.JWT_KEY;
import static cpe.atelier3.auth.domain.auth.jwt.JWTGenerator.TTL;
import static org.springframework.http.HttpStatus.UNAUTHORIZED;

@Service
public class AuthenticationService {
Expand Down Expand Up @@ -47,6 +48,12 @@ public Cookie authenticate(String username, String password) throws UserDoesNotE
}

public String checkAuthentication(String token) throws InvalidTokenException {
try {
if (checkServiceToken(token)) {
return ""; // ça risque de casser des choses si on essaye d'accéder à certains endpoint avec un token de service, à voir la stratégie à employer
}
} catch (ResponseStatusException ignored) {
}
try {
return Jwts.parser()
.verifyWith(JWT_KEY)
Expand All @@ -58,4 +65,11 @@ public String checkAuthentication(String token) throws InvalidTokenException {
throw new InvalidTokenException();
}
}

public boolean checkServiceToken(String token) {
if (! token.equals("secureservicetoken")) {
throw new ResponseStatusException(UNAUTHORIZED, "You are not authorized to access this endpoint.");
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
package cpe.atelier3.auth.domain.user;

import cpe.atelier3.commons.api.card.CardApi;
import cpe.atelier3.commons.api.user.UserApi;
import cpe.atelier3.commons.card.Card;
import cpe.atelier3.commons.card.exception.CardNotFoundException;
import cpe.atelier3.commons.user.UserPaymentRequest;
import cpe.atelier3.commons.user.dto.UserDtoMapper;
import cpe.atelier3.commons.user.exception.CardNotOwnedException;
import cpe.atelier3.commons.user.exception.UserNotFoundException;
import cpe.atelier3.commons.user.User;
import cpe.atelier3.commons.user.exception.UserPaymentInsufficientBalanceException;
import cpe.atelier3.commons.user.exception.UserSelfPaymentException;
import org.springframework.stereotype.Service;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Service
public class UserService {

private final IUserRepository iUserRepository;
private final UserDtoMapper userDtoMapper;
private final CardApi cardApi;

public UserService(IUserRepository iUserRepository) {
public UserService(IUserRepository iUserRepository, UserApi userApi, UserDtoMapper userDtoMapper, CardApi cardApi) {
this.iUserRepository = iUserRepository;
this.userDtoMapper = userDtoMapper;
this.cardApi = cardApi;
}

public List<User> findAll(){
Expand All @@ -34,4 +50,62 @@ public String insertUser(User user){
}
return "user already exist, aborting";
}

public void updateUser(User user) {
iUserRepository.insertUser(user);
}

public void processPayment(UserPaymentRequest userPaymentRequest) throws UserNotFoundException,
UserSelfPaymentException,
UserPaymentInsufficientBalanceException {
User buyer = findUserById(userPaymentRequest.buyerId());
User seller = findUserById(userPaymentRequest.sellerId());

if (buyer.equals(seller)) {
throw new UserSelfPaymentException();
}

if (buyer.money() < userPaymentRequest.withdrawalAmount()) {
throw new UserPaymentInsufficientBalanceException();
}

buyer.setMoney(buyer.money() - userPaymentRequest.withdrawalAmount());
seller.setMoney(seller.money() + userPaymentRequest.withdrawalAmount());

updateUser(seller);
updateUser(buyer);
}

public void removeCard(Long uid, Long cid) throws UserNotFoundException {
User user = findUserById(uid);

List<Card> newCards = user.cardList().stream()
.filter(card -> !Objects.equals(card.getId(), cid))
.toList();

user.setCardList(newCards);

updateUser(user);
}

public void addCard(Long uid, Long cid) throws URISyntaxException, CardNotFoundException, UserNotFoundException {
User user = findUserById(uid);

List<Card> newCards = new ArrayList<>(user.cardList());
newCards.add(cardApi.findCardById(cid));
user.setCardList(newCards);

updateUser(user);
}

public void getCardFromUser(Long uid, Long cid) throws UserNotFoundException, CardNotOwnedException {
User user = findUserById(uid);

List<Card> cards = user.cardList();

cards = cards.stream().filter(card -> card.getId() == cid)
.toList();

if (cards.isEmpty()) throw new CardNotOwnedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ public class AuthApiCookieUtils {
public static String formatToken(String token) {
return String.format("token=%s", token);
}

public static String formatServiceToken(String token) {
return String.format("service_token=%s", token);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package cpe.atelier3.commons.api.exception;

import lombok.Getter;
import org.springframework.web.bind.annotation.ResponseStatus;

@Getter
@ResponseStatus()
public class ApiNokException extends Exception {

private int errorCode;
Expand All @@ -8,7 +13,4 @@ public ApiNokException(int errorCode, String message) {
this.errorCode = errorCode;
}

public int getErrorCode() {
return this.errorCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@
import cpe.atelier3.commons.api.auth.utils.AuthApiCookieUtils;
import cpe.atelier3.commons.api.exception.ApiNokException;
import cpe.atelier3.commons.api.user.utils.UserURIUtils;
import cpe.atelier3.commons.market.MarketBuyRequest;
import cpe.atelier3.commons.user.User;
import cpe.atelier3.commons.user.UserPaymentRequest;
import cpe.atelier3.commons.user.dto.PrivateUserDTO;
import cpe.atelier3.commons.user.dto.UserDTO;
import cpe.atelier3.commons.user.dto.UserDtoMapper;
import cpe.atelier3.commons.user.dto.UserPaymentRequestDTO;
import cpe.atelier3.commons.user.exception.CardNotOwnedException;
import cpe.atelier3.commons.user.exception.UserNotFoundException;
import jakarta.servlet.http.Cookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;

import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
Expand Down Expand Up @@ -72,4 +79,75 @@ public User findUserById(Long id, String token) throws UserNotFoundException {
assert response != null;
return gson.fromJson(response.body(), User.class);
}

public void payUser(String token, UserPaymentRequestDTO userPaymentRequest) throws ResponseStatusException {
Gson gson = new Gson();
HttpRequest request;
request = HttpRequest.newBuilder()
.uri(userURIUtils.paymentToUser())
.header("Cookie", AuthApiCookieUtils.formatToken(token))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(gson.toJson(userPaymentRequest)))
.build();

HttpResponse<String> response = null;

try {
ApiUtils.sendRequestToApi(request, API_NAME, "Payment to user");
} catch (ApiNokException e) {
throw new ResponseStatusException(HttpStatusCode.valueOf(e.getErrorCode()), e.getMessage());
}
}

public void removeCard(String serviceToken, Long userId, Long cardId) {
HttpRequest request;
request = HttpRequest.newBuilder()
.uri(userURIUtils.cardOfUserManipulation(userId, cardId))
.header("Cookie", AuthApiCookieUtils.formatServiceToken(serviceToken))
.DELETE()
.build();

try {
ApiUtils.sendRequestToApi(request, API_NAME, "User card removal");
} catch (ApiNokException e) {
throw new ResponseStatusException(HttpStatusCode.valueOf(e.getErrorCode()), e.getMessage());
}
}

public void addCard(String serviceToken, Long userId, Long cardId) {
HttpRequest request;
request = HttpRequest.newBuilder()
.uri(userURIUtils.cardOfUserManipulation(userId, cardId))
.header("Cookie", AuthApiCookieUtils.formatServiceToken(serviceToken))
.PUT(HttpRequest.BodyPublishers.noBody()) // Idéalement ici j'aurais du mettre un DTO avec l'id de carte à ajouter mais le temps joue en ma défaveur
.build();

HttpResponse<String> response = null;

try {
ApiUtils.sendRequestToApi(request, API_NAME, "User card addition");
} catch (ApiNokException e) {
throw new ResponseStatusException(HttpStatusCode.valueOf(e.getErrorCode()), e.getMessage());
}
}

public void getCardOfUser(String serviceToken, Long userId, Long cardId) throws CardNotOwnedException {
HttpRequest request;
request = HttpRequest.newBuilder()
.uri(userURIUtils.cardOfUserManipulation(userId, cardId))
.header("Cookie", AuthApiCookieUtils.formatServiceToken(serviceToken))
.GET() // Idéalement ici j'aurais du mettre un DTO avec l'id de carte à ajouter mais le temps joue en ma défaveur
.build();

HttpResponse<String> response = null;

try {
ApiUtils.sendRequestToApi(request, API_NAME, "User card check");
} catch (ApiNokException e) {
if (e.getErrorCode() == 404) {
throw new CardNotOwnedException();
}
throw new ResponseStatusException(HttpStatusCode.valueOf(e.getErrorCode()), e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,22 @@ public URI privateUserInfo() {
.getUri()
.resolve("/user/private");
}

public URI paymentToUser() {
return discoveryClient.getInstances("card-auth").get(0)
.getUri()
.resolve("/user/private/payment");
}

public URI cardOfUserManipulation(Long uid, Long cid) {
return discoveryClient.getInstances("card-auth").get(0)
.getUri()
.resolve("/user/" + uid.toString() + "/card/" + cid.toString());
}

public URI getCardOfUser(Long uid, Long cid) {
return discoveryClient.getInstances("card-auth").get(0)
.getUri()
.resolve("/user/" + uid.toString() + "/card/" + cid.toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cpe.atelier3.commons.market;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@AllArgsConstructor
@Getter
@Setter
public class MarketBuyRequest {
public Long buyerId;
public Long marketOfferId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package cpe.atelier3.commons.market.dto;

public record MarketBuyRequestDTO(Long userId, Long marketOfferId) {
}
Loading
Loading