SpringBoot introduce GameProposalController

This commit is contained in:
djmil 2023-09-03 20:38:40 +02:00
parent 36edc91cf3
commit 7a2a366dd5
11 changed files with 97 additions and 91 deletions

View File

@ -1,43 +0,0 @@
package djmil.cordacheckers;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import djmil.cordacheckers.cordaclient.HoldingIdentityResolver;
import djmil.cordacheckers.cordaclient.dao.HoldingIdentity;
@Service
public class ApiUserDetailsService implements UserDetailsService {
private final PasswordEncoder encoder;
private final HoldingIdentityResolver holdingIdentityResolver;
public ApiUserDetailsService(
PasswordEncoder encoder,
HoldingIdentityResolver holdingIdentityNameResolver) {
this.encoder = encoder;
this.holdingIdentityResolver = holdingIdentityNameResolver;
}
@Override
public ApiUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
HoldingIdentity holdingIdentity = holdingIdentityResolver.getByCommonName(username);
if (holdingIdentity == null) {
throw new UsernameNotFoundException("Can't find HoldingIdentity for the user '"+username+ "'");
}
System.out.println("Load user "+username);
User.UserBuilder userBuilder = User.builder();
UserDetails user = userBuilder
.username(username)
.password(encoder.encode("qaz123"))
.build();
return new ApiUserDetails(user, holdingIdentity);
}
}

View File

@ -17,12 +17,12 @@ import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import djmil.cordacheckers.cordaclient.dao.HoldingIdentity;
import djmil.cordacheckers.cordaclient.dao.Color;
import djmil.cordacheckers.cordaclient.dao.VirtualNode;
import djmil.cordacheckers.cordaclient.dao.VirtualNodeList;
import djmil.cordacheckers.cordaclient.dao.flow.RequestBody;
import djmil.cordacheckers.cordaclient.dao.flow.ResponseBody;
import djmil.cordacheckers.cordaclient.dao.flow.arguments.Empty;
import djmil.cordacheckers.game.PlayerColor;
@Service
public class CordaClient {
@ -73,7 +73,12 @@ public class CordaClient {
return gameProposalsJsonString;
}
public String sendGameProposal(HoldingIdentity sender, HoldingIdentity receiver, PlayerColor receiverColor, String message) {
public String sendGameProposal(
HoldingIdentity sender,
HoldingIdentity receiver,
Color receiverColor,
String message
) {
return "";
}

View File

@ -0,0 +1,6 @@
package djmil.cordacheckers.cordaclient.dao;
public enum Color {
WHITE,
BLACK
}

View File

@ -6,8 +6,8 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public record GameProposal(
String sender,
String recipient,
String youPlayAs,
String additionalMessage,
Color recipientColor,
String message,
String id) {
}

View File

@ -1,6 +0,0 @@
package djmil.cordacheckers.game;
public enum PlayerColor {
WHITE,
BLACK
}

View File

@ -1,9 +0,0 @@
package djmil.cordacheckers.gameproposal;
public record CreateGameProposal(
String opponentName,
String opponentColor,
String message)
{
}

View File

@ -0,0 +1,12 @@
package djmil.cordacheckers.gameproposal;
import djmil.cordacheckers.cordaclient.dao.Color;
public record GameProposal(
String sender,
String recipient,
Color recipientColor,
String message)
{
}

View File

@ -1,4 +1,4 @@
package djmil.cordacheckers;
package djmil.cordacheckers.gameproposal;
import java.net.URI;
import java.util.List;
@ -11,11 +11,10 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import djmil.cordacheckers.cordaclient.CordaClient;
import djmil.cordacheckers.cordaclient.HoldingIdentityResolver;
import djmil.cordacheckers.cordaclient.dao.HoldingIdentity;
import djmil.cordacheckers.cordaclient.dao.VirtualNode;
import djmil.cordacheckers.game.PlayerColor;
import djmil.cordacheckers.gameproposal.CreateGameProposal;
import djmil.cordacheckers.cordaclient.dao.Color;
import djmil.cordacheckers.user.HoldingIdentityResolver;
import djmil.cordacheckers.user.User;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -23,7 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
@RestController
@RequestMapping("/gameproposal")
@RequestMapping("gameproposal")
public class GameProposalController {
@Autowired
@ -34,9 +33,9 @@ public class GameProposalController {
@GetMapping
public ResponseEntity<String> findAllUnconsumed(
@AuthenticationPrincipal ApiUserDetails user
@AuthenticationPrincipal User player
) {
String gpList = cordaClient.listGameProposals(user.getHoldingIdentity());
String gpList = cordaClient.listGameProposals(player.getHoldingIdentity());
return ResponseEntity.ok(gpList);
}
@ -48,15 +47,17 @@ public class GameProposalController {
// }
@PostMapping()
public ResponseEntity<Void> create(
@AuthenticationPrincipal ApiUserDetails player,
@RequestBody CreateGameProposal gpRequest,
public ResponseEntity<Void> createGameProposal(
@AuthenticationPrincipal User sender,
@RequestBody GameProposal gpRequest,
UriComponentsBuilder ucb
) {
final HoldingIdentity gpSender = player.getHoldingIdentity();
//sender.get
final HoldingIdentity gpSender = sender.getHoldingIdentity();
// TODO: throw execption with custom type
final HoldingIdentity gpReceiver = holdingIdentityResolver.getByCommonName(gpRequest.opponentName());
final PlayerColor gpReceiverColor = PlayerColor.valueOf(gpRequest.opponentColor());
final HoldingIdentity gpReceiver = holdingIdentityResolver.getByUsername(gpRequest.recipient());
final Color gpReceiverColor = gpRequest.recipientColor();
String newGameProposalUuid = cordaClient.sendGameProposal(
gpSender,

View File

@ -1,4 +1,4 @@
package djmil.cordacheckers.cordaclient;
package djmil.cordacheckers.user;
import java.util.HashMap;
import java.util.List;
@ -9,6 +9,7 @@ import javax.naming.InvalidNameException;
import org.springframework.stereotype.Service;
import djmil.cordacheckers.cordaclient.CordaClient;
import djmil.cordacheckers.cordaclient.dao.HoldingIdentity;
import djmil.cordacheckers.cordaclient.dao.VirtualNode;
@ -18,10 +19,10 @@ public class HoldingIdentityResolver {
/*
* NOTE: Proof-of-Concept impementation
* Ideally, we want to be able to update HoldingIdentity cache, had the
* corda cluster configuration changed (aka in case of a cache miss)
* Ideally, we want to be able to force update cache, had the corda
* cluster configuration changed (aka in case of a cache miss)
*/
final Map<String, HoldingIdentity> cache;
final Map<String, HoldingIdentity> cache; // PlayerName to ShortHash
HoldingIdentityResolver(CordaClient cordaClient) {
this.cache = setCache(cordaClient);
@ -37,27 +38,29 @@ public class HoldingIdentityResolver {
var identity = vNode.holdingIdentity();
if (identity.isPlayer()) {
map.put(identity.getName().toLowerCase(locale), identity);
map.put(
identity.getName().toLowerCase(locale),
identity
);
}
}
} catch (InvalidNameException e) {
// TODO: logs
System.out.println("Unable to get ShorHash map for Corda virtual nodes: "+e.getExplanation());
e.printStackTrace();
System.out.println("Unable to get ShorHash list of Corda VirtualNodes: "+e.getMessage());
}
return map;
}
/*
* @param apiUserName
* @param playerName
* HoldingIdentity x500 name typically looks like
* "CN=Bob, OU=Player, O=Checkers, L=Kviv, C=UA"
* CN - is a common name, expected to be unique for CordaCheckers setup.
*
* @return HoldingIdentity
*/
public HoldingIdentity getByCommonName(String apiUserName) {
return this.cache.get(apiUserName.toLowerCase(locale));
public HoldingIdentity getByUsername(String userName) {
return this.cache.get(userName.toLowerCase(locale));
}
}

View File

@ -1,14 +1,13 @@
package djmil.cordacheckers;
package djmil.cordacheckers.user;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import djmil.cordacheckers.cordaclient.dao.HoldingIdentity;
public class ApiUserDetails extends User {
public class User extends org.springframework.security.core.userdetails.User {
private final HoldingIdentity holdingIdentity;
public ApiUserDetails(UserDetails user, HoldingIdentity holdingIdentity) {
public User(UserDetails user, HoldingIdentity holdingIdentity) {
super(user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), user.getAuthorities());
this.holdingIdentity = holdingIdentity;
@ -17,5 +16,4 @@ public class ApiUserDetails extends User {
public HoldingIdentity getHoldingIdentity() {
return this.holdingIdentity;
}
}

View File

@ -0,0 +1,39 @@
package djmil.cordacheckers.user;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserService implements UserDetailsService {
private final PasswordEncoder encoder;
private final HoldingIdentityResolver holdingIdentityResolver;
public UserService(
PasswordEncoder encoder,
HoldingIdentityResolver holdingIdentityResolver) {
this.encoder = encoder;
this.holdingIdentityResolver = holdingIdentityResolver;
}
@Override
public User loadUserByUsername(String username) throws UsernameNotFoundException {
final var holdingIdentity = this.holdingIdentityResolver.getByUsername(username);
if (holdingIdentity == null) {
throw new UsernameNotFoundException("Can't find HoldingIdentity for the user '"+username+ "'");
}
System.out.println("Load user "+username);
org.springframework.security.core.userdetails.User.UserBuilder userBuilder = org.springframework.security.core.userdetails.User.builder();
UserDetails baseUser = userBuilder
.username(username)
.password(this.encoder.encode("qaz123"))
.build();
return new User(baseUser, holdingIdentity);
}
}