Move to new server
This commit is contained in:
15
src/main/java/nl/connectedit/swiss/SwissApplication.java
Executable file
15
src/main/java/nl/connectedit/swiss/SwissApplication.java
Executable file
@@ -0,0 +1,15 @@
|
||||
package nl.connectedit.swiss;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableTransactionManagement
|
||||
public class SwissApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SwissApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@RestController
|
||||
@ConditionalOnExpression("${security}")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class AuthenticationController {
|
||||
|
||||
private final JwtUserDetailsService jwtUserDetailsService;
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
private final JwtTokenService jwtTokenService;
|
||||
|
||||
@PostMapping("/authenticate")
|
||||
public AuthenticationResponse authenticate(@RequestBody @Valid final AuthenticationRequest authenticationRequest) {
|
||||
try {
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
|
||||
authenticationRequest.getUsername(), authenticationRequest.getPassword()));
|
||||
} catch (final BadCredentialsException ex) {
|
||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
final UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(authenticationRequest.getUsername());
|
||||
final AuthenticationResponse authenticationResponse = new AuthenticationResponse();
|
||||
authenticationResponse.setAccessToken(jwtTokenService.generateToken(userDetails));
|
||||
authenticationResponse.setUsername(authenticationRequest.getUsername());
|
||||
return authenticationResponse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class AuthenticationRequest {
|
||||
|
||||
@NotNull
|
||||
@Size(max = 255)
|
||||
private String username;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 255)
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class AuthenticationResponse {
|
||||
|
||||
private String accessToken;
|
||||
|
||||
private String username;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Client {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String hash;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class ClientRepository {
|
||||
|
||||
private static final String hash = "$2a$12$FjsFqFTorg0sXCiSISFS3.xvSCzmAATIcA7wh5w8WtQ7eYZC.H4UW";
|
||||
|
||||
Optional<Client> findByLogin(String username) {
|
||||
if (username.equals("bcholten")) {
|
||||
var client = new Client();
|
||||
client.setId(1L);
|
||||
client.setHash(hash);
|
||||
return Optional.of(client);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
@ConditionalOnExpression("${security}")
|
||||
@RequiredArgsConstructor
|
||||
public class JwtRequestFilter extends OncePerRequestFilter {
|
||||
|
||||
private final JwtTokenService jwtTokenService;
|
||||
|
||||
private final JwtUserDetailsService jwtUserDetailsService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
|
||||
final FilterChain chain) throws IOException, ServletException {
|
||||
// look for Bearer auth header
|
||||
final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
if (header == null || !header.startsWith("Bearer ")) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
final String token = header.substring(7);
|
||||
final String username = jwtTokenService.validateTokenAndGetUsername(token);
|
||||
if (username == null) {
|
||||
// validation failed or token expired
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// set user details on spring security context
|
||||
final JwtUserDetails userDetails = jwtUserDetailsService.loadUserByUsername(username);
|
||||
final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
// continue with authenticated user
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnExpression("${security}")
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class JwtSecurityConfig {
|
||||
|
||||
private final JwtRequestFilter jwtRequestFilter;
|
||||
|
||||
@Bean
|
||||
BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(
|
||||
final AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain configure(final HttpSecurity http) throws Exception {
|
||||
return http.cors(withDefaults())
|
||||
.csrf((csrf) -> csrf.disable())
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers("/", "/authenticate", "/testdata").permitAll()
|
||||
.anyRequest().hasAuthority(UserRoles.ROLE_USER))
|
||||
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurer corsConfigurer() {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
@Service
|
||||
@ConditionalOnExpression("${security}")
|
||||
public class JwtTokenService {
|
||||
|
||||
private static final Duration JWT_TOKEN_VALIDITY = Duration.ofDays(7);
|
||||
|
||||
private final Algorithm rsa256;
|
||||
private final JWTVerifier verifier;
|
||||
|
||||
public JwtTokenService(@Value("classpath:certs/public.pem") final RSAPublicKey publicKey,
|
||||
@Value("classpath:certs/private.pem") final RSAPrivateKey privateKey) {
|
||||
this.rsa256 = Algorithm.RSA256(publicKey, privateKey);
|
||||
this.verifier = JWT.require(this.rsa256).build();
|
||||
}
|
||||
|
||||
public String generateToken(final UserDetails userDetails) {
|
||||
final Instant now = Instant.now();
|
||||
return JWT.create()
|
||||
.withSubject(userDetails.getUsername())
|
||||
.withIssuer("app")
|
||||
.withIssuedAt(now)
|
||||
.withExpiresAt(now.plusMillis(JWT_TOKEN_VALIDITY.toMillis()))
|
||||
.sign(this.rsa256);
|
||||
}
|
||||
|
||||
public String validateTokenAndGetUsername(final String token) {
|
||||
try {
|
||||
return verifier.verify(token).getSubject();
|
||||
} catch (final JWTVerificationException verificationEx) {
|
||||
// log.warn("token invalid: {}", verificationEx.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JwtUserDetails extends User {
|
||||
|
||||
public final Long id;
|
||||
|
||||
public JwtUserDetails(final Long id, final String username, final String hash,
|
||||
final Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, hash, authorities);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class JwtUserDetailsService implements UserDetailsService {
|
||||
|
||||
private final ClientRepository clientRepository;
|
||||
|
||||
@Override
|
||||
public JwtUserDetails loadUserByUsername(final String username) {
|
||||
final Client client = clientRepository.findByLogin(username).orElseThrow(
|
||||
() -> new UsernameNotFoundException("User " + username + " not found"));
|
||||
final List<SimpleGrantedAuthority> roles = Collections.singletonList(new SimpleGrantedAuthority(UserRoles.ROLE_USER));
|
||||
return new JwtUserDetails(client.getId(), username, client.getHash(), roles);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LoginCredentialsDto {
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String ipAddres;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserDto {
|
||||
|
||||
private String username;
|
||||
|
||||
private String token;
|
||||
|
||||
private String refreshToken;
|
||||
|
||||
private String ipAddress;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package nl.connectedit.swiss.authentication;
|
||||
|
||||
public class UserRoles {
|
||||
|
||||
public static final String USER = "USER";
|
||||
public static final String ROLE_USER = "ROLE_" + USER;
|
||||
|
||||
}
|
||||
25
src/main/java/nl/connectedit/swiss/config/CorsConfig.java
Normal file
25
src/main/java/nl/connectedit/swiss/config/CorsConfig.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package nl.connectedit.swiss.config;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
//@Component
|
||||
public class CorsConfig extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
|
||||
final FilterChain filterChain) throws ServletException, IOException {
|
||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||
response.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD");
|
||||
response.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
|
||||
response.addHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials");
|
||||
response.addHeader("Access-Control-Allow-Credentials", "true");
|
||||
response.addIntHeader("Access-Control-Max-Age", 10);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
14
src/main/java/nl/connectedit/swiss/config/JsonConfig.java
Normal file
14
src/main/java/nl/connectedit/swiss/config/JsonConfig.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package nl.connectedit.swiss.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class JsonConfig {
|
||||
@Bean
|
||||
public Module hibernateModule() {
|
||||
return new Hibernate5JakartaModule();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package nl.connectedit.swiss.config;
|
||||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
//@Configuration
|
||||
//@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
// @Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
|
||||
// .authorizeHttpRequests(request -> {
|
||||
// request.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll();
|
||||
// request.requestMatchers("/error").permitAll();
|
||||
// });
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.dto.PlayerDto;
|
||||
import nl.connectedit.swiss.mapper.PlayerMapper;
|
||||
import nl.connectedit.swiss.service.PlayerService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequiredArgsConstructor
|
||||
public class PlayerController {
|
||||
|
||||
private final PlayerService playerService;
|
||||
|
||||
private final PlayerMapper playerMapper;
|
||||
|
||||
@GetMapping("/players")
|
||||
public ResponseEntity<List<PlayerDto>> getPlayers() {
|
||||
return ResponseEntity.ok(playerService.findAllPlayers()
|
||||
.stream()
|
||||
.map(playerMapper::toDto)
|
||||
.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/players/{id}")
|
||||
public ResponseEntity<PlayerDto> getPlayer(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(playerMapper.toDto(playerService.findPlayerById(id)));
|
||||
}
|
||||
|
||||
@PostMapping("/players")
|
||||
public ResponseEntity<PlayerDto> createPlayer(@RequestBody PlayerDto playerDto) {
|
||||
Player player;
|
||||
try {
|
||||
player = playerMapper.toEntity(playerDto);
|
||||
} catch (NullPointerException e) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
return ResponseEntity.ok(playerMapper.toDto(playerService.savePlayer(player)));
|
||||
}
|
||||
|
||||
@PutMapping("/players/{id}")
|
||||
public ResponseEntity<PlayerDto> updatePlayer(@PathVariable("id") Long id, @RequestBody PlayerDto playerDto) {
|
||||
var player = playerMapper.toEntity(playerDto);
|
||||
player.setId(id);
|
||||
return ResponseEntity.ok(playerMapper.toDto(playerService.savePlayer(player)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.dto.TournamentRegistrationDto;
|
||||
import nl.connectedit.swiss.mapper.TournamentPlayerRegistrationMapper;
|
||||
import nl.connectedit.swiss.service.PlayerService;
|
||||
import nl.connectedit.swiss.service.RegistrationService;
|
||||
import nl.connectedit.swiss.service.TournamentService;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequiredArgsConstructor
|
||||
public class RegistrationController {
|
||||
|
||||
private final PlayerService playerService;
|
||||
|
||||
private final RegistrationService registrationService;
|
||||
|
||||
private final TournamentService tournamentService;
|
||||
|
||||
private final TournamentPlayerRegistrationMapper tournamentPlayerRegistrationMapper;
|
||||
|
||||
@GetMapping("/players/{playerId}/registrations")
|
||||
public List<TournamentRegistrationDto> getRegistrationsForPlayer(@PathVariable Long playerId) {
|
||||
var player = playerService.findPlayerById(playerId);
|
||||
var tournaments = tournamentService.findAllTournaments();
|
||||
|
||||
return tournamentPlayerRegistrationMapper.mapToDto(tournaments, player);
|
||||
}
|
||||
|
||||
@PostMapping("/players/{playerId}/registrations/{tournamentId}")
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
public TournamentRegistrationDto registerTournamentRegistrations(@PathVariable Long playerId, @PathVariable Long tournamentId, @RequestBody TournamentRegistrationDto tournamentRegistrationDto) {
|
||||
var player = playerService.findPlayerById(playerId);
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
for (var eventRegistration : tournamentRegistrationDto.getEvents()) {
|
||||
registrationService.updateOrAddRegistrations(eventRegistration, tournament, player);
|
||||
}
|
||||
|
||||
return tournamentPlayerRegistrationMapper.mapToTournamentRegistrationDto(tournament, player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
//@ControllerAdvice
|
||||
public class RestResponseEntityExceptionHandler
|
||||
extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ExceptionHandler({AccessDeniedException.class})
|
||||
public ResponseEntity<Object> handleAccessDeniedException(
|
||||
Exception ex, WebRequest request) {
|
||||
return new ResponseEntity<Object>(ex.getMessage(), new HttpHeaders(), HttpStatus.FORBIDDEN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import nl.connectedit.swiss.domain.*;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.domain.entity.Registration;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.domain.entity.TournamentPlayer;
|
||||
import nl.connectedit.swiss.dto.*;
|
||||
import nl.connectedit.swiss.service.*;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static nl.connectedit.swiss.domain.PlayerStrength.*;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequiredArgsConstructor
|
||||
public class TestController {
|
||||
|
||||
private final TournamentService tournamentService;
|
||||
|
||||
private final PlayerService playerService;
|
||||
|
||||
private final TournamentDivideService tournamentDivideService;
|
||||
private final TournamentDrawService tournamentDrawService;
|
||||
private final TournamentPlayService tournamentPlayService;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final RestTemplateBuilder restTemplateBuilder;
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
private final PlayerController playerController;
|
||||
|
||||
private String authorizationHeader;
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@GetMapping("/testdata")
|
||||
// @PostConstruct
|
||||
// @Transactional
|
||||
public void init(@RequestHeader(name = "Authorization", required = false) String authorizationHeader) {
|
||||
this.authorizationHeader = authorizationHeader;
|
||||
|
||||
restTemplate = restTemplateBuilder.build();
|
||||
|
||||
var tournament = createTournament();
|
||||
|
||||
getMales().forEach(player -> savePlayer(player, Sex.M));
|
||||
getFemales().forEach(player -> savePlayer(player, Sex.V));
|
||||
|
||||
registerForSingles(tournament);
|
||||
registerForDoubles(tournament);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
private List<PlayerDto> getPlayers() {
|
||||
var headers = new HttpHeaders();
|
||||
headers.add("Authorization", authorizationHeader);
|
||||
var entity = new HttpEntity<>(headers);
|
||||
|
||||
// return Arrays.asList(restTemplate.getForEntity("http://localhost:8080/players", PlayerDto[].class).getBody());
|
||||
return Arrays.asList(restTemplate.exchange("http://localhost:8080/players", HttpMethod.GET, entity, PlayerDto[].class).getBody());
|
||||
}
|
||||
|
||||
private void registerForSingles(TournamentDto tournament) {
|
||||
var eventIdHE = tournament.getEvents().stream().filter(event -> event.getType().equals("HE")).findFirst().get().getId();
|
||||
var eventIdDE = tournament.getEvents().stream().filter(event -> event.getType().equals("DE")).findFirst().get().getId();
|
||||
|
||||
for (var player : getPlayers()) {
|
||||
var tournamentRegistrationDto = new TournamentRegistrationDto();
|
||||
tournamentRegistrationDto.setId(tournament.getId());
|
||||
var eventRegistrationDto = new EventRegistrationDto();
|
||||
eventRegistrationDto.setId(player.getSex().equals("M") ? eventIdHE : eventIdDE);
|
||||
eventRegistrationDto.setRegistered(true);
|
||||
eventRegistrationDto.setPlayer(player.getId());
|
||||
eventRegistrationDto.setType(player.getSex().equals("M") ? "HE" : "DE");
|
||||
tournamentRegistrationDto.setEvents(List.of(eventRegistrationDto));
|
||||
|
||||
var headers = new HttpHeaders();
|
||||
headers.add("Authorization", authorizationHeader);
|
||||
var entity = new HttpEntity<>(tournamentRegistrationDto, headers);
|
||||
restTemplate.postForObject("http://localhost:8080/players/%d/registrations/%d".formatted(player.getId(), tournament.getId()), entity, TournamentRegistrationDto.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerForDoubles(TournamentDto tournament) {
|
||||
var males = getPlayers().stream().filter(p -> p.getSex().equals("M")).toArray(PlayerDto[]::new);
|
||||
var females = getPlayers().stream().filter(p -> p.getSex().equals("V")).toArray(PlayerDto[]::new);
|
||||
|
||||
for (int i = 0; i <= 6; i++) {
|
||||
registerForDoubles(tournament, males[i * 2], males[i * 2 + 1]);
|
||||
registerForDoubles(tournament, males[i * 2 + 1], males[i * 2]);
|
||||
}
|
||||
for (int i = 0; i <= 8; i++) {
|
||||
registerForDoubles(tournament, females[i * 2], females[i * 2 + 1]);
|
||||
registerForDoubles(tournament, females[i * 2 + 1], females[i * 2]);
|
||||
}
|
||||
for (int i = 18; i <= 29; i++) {
|
||||
registerForDoubles(tournament, males[i], females[i]);
|
||||
registerForDoubles(tournament, females[i], males[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void registerForDoubles(TournamentDto tournament, PlayerDto player, PlayerDto partner) {
|
||||
var eventType = player.getSex().equals(partner.getSex()) ? (player.getSex().equals("M") ? "HD" : "DD") : "GD";
|
||||
|
||||
var eventId = tournament.getEvents().stream().filter(event -> event.getType().equals(eventType)).findFirst().get().getId();
|
||||
|
||||
// for (var player : getPlayers()) {
|
||||
var tournamentRegistrationDto = new TournamentRegistrationDto();
|
||||
tournamentRegistrationDto.setId(tournament.getId());
|
||||
var eventRegistrationDto = new EventRegistrationDto();
|
||||
eventRegistrationDto.setId(eventId);
|
||||
eventRegistrationDto.setRegistered(true);
|
||||
eventRegistrationDto.setPlayer(player.getId());
|
||||
eventRegistrationDto.setPartner(partner.getId());
|
||||
eventRegistrationDto.setType(eventType);
|
||||
tournamentRegistrationDto.setEvents(List.of(eventRegistrationDto));
|
||||
|
||||
var headers = new HttpHeaders();
|
||||
headers.add("Authorization", authorizationHeader);
|
||||
var entity = new HttpEntity<>(tournamentRegistrationDto, headers);
|
||||
restTemplate.postForObject("http://localhost:8080/players/%d/registrations/%d".formatted(player.getId(), tournament.getId()), entity, TournamentRegistrationDto.class);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
private TournamentDto createTournament() {
|
||||
var headers = new HttpHeaders();
|
||||
headers.add("Authorization", authorizationHeader);
|
||||
var entity = new HttpEntity<>(getTournament(), headers);
|
||||
return restTemplate.postForObject("http://localhost:8080/tournaments", entity, TournamentDto.class);
|
||||
}
|
||||
|
||||
private TournamentDto getTournament() {
|
||||
var tournamentDto = new TournamentDto();
|
||||
tournamentDto.setName("Testtoernooi");
|
||||
tournamentDto.setDate("14-12-2024");
|
||||
tournamentDto.setStatus("UPCOMING");
|
||||
tournamentDto.setMaxEvents(2L);
|
||||
tournamentDto.setCourts(9L);
|
||||
tournamentDto.setCostsPerEvent(List.of(6f, 10f, 0f));
|
||||
return tournamentDto;
|
||||
}
|
||||
|
||||
private void savePlayer(String firstName, Sex sex) {
|
||||
Random random = new Random();
|
||||
|
||||
String[] lastNames = {
|
||||
"Meedendorp", "Holstege", "Goedhart", "Zijlma", "Duursma", "Keizer", "Verschoor",
|
||||
"Mulder", "Koers", "Duindam", "Castelein", "Coemans", "Huijbers", "Kelder",
|
||||
"Stein", "Rakhorst", "Brugman", "Seinen", "Mayer", "Gijsman", "Kingma",
|
||||
"Jansen", "Westerik", "Brehler", "Ebbers", "Lensink", "Lups", "Verboom"
|
||||
};
|
||||
|
||||
String[] clubs = {
|
||||
"BC Holten", "BC Reflex", "ZBC", "WSV Apeldoorn", "BC IJsselstad", "Flits", "ELO United", "BC Kwiek"
|
||||
};
|
||||
|
||||
var playerDto = new PlayerDto();
|
||||
playerDto.setFirstName(firstName);
|
||||
playerDto.setLastName(lastNames[random.nextInt(lastNames.length)]);
|
||||
playerDto.setClub(clubs[random.nextInt(clubs.length)]);
|
||||
playerDto.setSex(sex.name());
|
||||
var birthday = randomDate(LocalDate.of(1950, 1, 1), LocalDate.of(2010, 1, 1)).format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
|
||||
playerDto.setBirthday(birthday);
|
||||
playerDto.setPhoneNumber("0612345678");
|
||||
playerDto.setEmail("aaaa@bbb.cc");
|
||||
playerDto.setStrength(getRandomStrength().name());
|
||||
|
||||
var headers = new HttpHeaders();
|
||||
headers.add("Authorization", authorizationHeader);
|
||||
var entity = new HttpEntity<>(playerDto, headers);
|
||||
restTemplate.postForObject("http://localhost:8080/players", entity, PlayerDto.class);
|
||||
}
|
||||
|
||||
private List<String> getMales() {
|
||||
return List.of("Michel", "Eric", "Leon", "Luuk", "Jeffrey", "Jason", "Oleg", "Gerjan", "Gerard", "Henk",
|
||||
"Peter", "Gerrit", "Wilco", "Guido", "Sander", "Roy", "Yafiq", "Martijn", "Dick", "Willem", "Layo",
|
||||
"Thomas", "Gerben", "Bert", "Bart", "Nico", "Jan", "Diederik", "Gert", "Dennis", "Pieter");
|
||||
}
|
||||
|
||||
private List<String> getFemales() {
|
||||
return List.of("Amber", "Lisa", "Vanja", "Evelien", "Daphne", "Willemijn", "Miranda", "Inge", "Esmee",
|
||||
"Joanne", "Laura", "Nienke", "Patty", "Rosan", "Vera", "Hedwig", "Lois", "Liedewij", "Gera", "Carolien",
|
||||
"Anne", "Dominique", "Linda", "Esther", "Marilyn", "Ilse", "Emily", "Eva", "Kitty", "Floor", "Tess", "Fenna");
|
||||
}
|
||||
|
||||
private PlayerStrength getRandomStrength() {
|
||||
var random = new Random().nextInt(0, 12);
|
||||
|
||||
return switch(random) {
|
||||
case 0 -> D5;
|
||||
case 1, 2 -> D6;
|
||||
case 3, 4, 5 -> D7;
|
||||
case 6, 7 -> D8;
|
||||
case 8, 9 -> D9;
|
||||
default -> DR;
|
||||
};
|
||||
}
|
||||
|
||||
public static LocalDate randomDate(LocalDate startInclusive, LocalDate endExclusive) {
|
||||
long startEpochDay = startInclusive.toEpochDay();
|
||||
long endEpochDay = endExclusive.toEpochDay();
|
||||
long randomDay = ThreadLocalRandom
|
||||
.current()
|
||||
.nextLong(startEpochDay, endEpochDay);
|
||||
|
||||
return LocalDate.ofEpochDay(randomDay);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
private void deRest() {
|
||||
|
||||
var malePlayers = List.of(
|
||||
savePlayer("Michel", Sex.M),
|
||||
savePlayer("Eric", Sex.M),
|
||||
savePlayer("Leon", Sex.M),
|
||||
savePlayer("Luuk", Sex.M),
|
||||
savePlayer("Jeffrey", Sex.M),
|
||||
savePlayer("Jason", Sex.M),
|
||||
savePlayer("Oleg", Sex.M),
|
||||
savePlayer("Gerjan", Sex.M),
|
||||
savePlayer("Gerard", Sex.M),
|
||||
savePlayer("Henk", Sex.M),
|
||||
savePlayer("Peter", Sex.M),
|
||||
savePlayer("Gerrit", Sex.M),
|
||||
savePlayer("Wilco", Sex.M),
|
||||
savePlayer("Guido", Sex.M),
|
||||
savePlayer("Sander", Sex.M),
|
||||
savePlayer("Roy", Sex.M),
|
||||
|
||||
savePlayer("Yafiq", Sex.M),
|
||||
savePlayer("Martijn", Sex.M),
|
||||
savePlayer("Dick", Sex.M),
|
||||
savePlayer("Willem", Sex.M),
|
||||
savePlayer("Layo", Sex.M),
|
||||
savePlayer("Thomas", Sex.M),
|
||||
savePlayer("Gerben", Sex.M),
|
||||
savePlayer("Bert", Sex.M),
|
||||
savePlayer("Bart", Sex.M),
|
||||
savePlayer("Nico", Sex.M),
|
||||
savePlayer("Jan", Sex.M),
|
||||
savePlayer("Diederik", Sex.M),
|
||||
savePlayer("Gert", Sex.M),
|
||||
savePlayer("Dennis", Sex.M),
|
||||
savePlayer("Pieter", Sex.M)
|
||||
);
|
||||
|
||||
var femalePlayers = List.of(
|
||||
savePlayer("Amber", Sex.V),
|
||||
savePlayer("Lisa", Sex.V),
|
||||
savePlayer("Vanja", Sex.V),
|
||||
savePlayer("Evelien", Sex.V),
|
||||
savePlayer("Daphne", Sex.V),
|
||||
savePlayer("Willemijn", Sex.V),
|
||||
savePlayer("Miranda", Sex.V),
|
||||
savePlayer("Inge", Sex.V),
|
||||
savePlayer("Esmee", Sex.V),
|
||||
savePlayer("Joanne", Sex.V),
|
||||
savePlayer("Laura", Sex.V),
|
||||
savePlayer("Nienke", Sex.V),
|
||||
savePlayer("Patty", Sex.V),
|
||||
savePlayer("Rosan", Sex.V),
|
||||
savePlayer("Vera", Sex.V),
|
||||
savePlayer("Hedwig", Sex.V),
|
||||
|
||||
savePlayer("Lois", Sex.V),
|
||||
savePlayer("Liedewij", Sex.V),
|
||||
savePlayer("Gera", Sex.V),
|
||||
savePlayer("Carolien", Sex.V),
|
||||
savePlayer("Anne", Sex.V),
|
||||
savePlayer("Dominique", Sex.V),
|
||||
savePlayer("Linda", Sex.V),
|
||||
savePlayer("Esther", Sex.V),
|
||||
savePlayer("Marilyn", Sex.V),
|
||||
savePlayer("Ilse", Sex.V),
|
||||
savePlayer("Emily", Sex.V),
|
||||
savePlayer("Eva", Sex.V),
|
||||
savePlayer("Kitty", Sex.V),
|
||||
savePlayer("Floor", Sex.V),
|
||||
savePlayer("Tess", Sex.V),
|
||||
savePlayer("Fenna", Sex.V)
|
||||
);
|
||||
|
||||
malePlayers.forEach(player -> registerForSingles(tournamentId, player));
|
||||
femalePlayers.forEach(player -> registerForSingles(tournamentId, player));
|
||||
|
||||
malePlayers = new ArrayList<>(malePlayers);
|
||||
malePlayers.add(savePlayer("Rolf", Sex.M));
|
||||
|
||||
for (var i = 0; i < 14; i += 2) {
|
||||
registerForDoubles(tournamentId, malePlayers.get(i), malePlayers.get(i + 1));
|
||||
registerForDoubles(tournamentId, malePlayers.get(i + 1), malePlayers.get(i));
|
||||
}
|
||||
for (var i = 0; i < 16; i += 2) {
|
||||
registerForDoubles(tournamentId, femalePlayers.get(i), femalePlayers.get(i + 1));
|
||||
registerForDoubles(tournamentId, femalePlayers.get(i + 1), femalePlayers.get(i));
|
||||
}
|
||||
for (var i = 16; i < malePlayers.size(); i++) {
|
||||
registerForDoubles(tournamentId, malePlayers.get(i), femalePlayers.get(i));
|
||||
registerForDoubles(tournamentId, femalePlayers.get(i), malePlayers.get(i));
|
||||
}
|
||||
|
||||
divideTournament(tournamentId);
|
||||
drawTournament(tournamentId);
|
||||
// startRound(2L, 1L);
|
||||
// playRound(2L, 0, 0);
|
||||
|
||||
startRound(tournamentId, 2L);
|
||||
playRound(tournamentId, 1, 0);
|
||||
|
||||
|
||||
finishRound(tournamentId, 2L);
|
||||
newRound(tournamentId, 2L);
|
||||
|
||||
startRound(tournamentId, 8L);
|
||||
playRound(tournamentId, 1, 1);
|
||||
|
||||
if (1==1) return;
|
||||
|
||||
finishRound(tournamentId, 8L);
|
||||
newRound(tournamentId, 2L);
|
||||
|
||||
startRound(tournamentId, 9L);
|
||||
playRound(tournamentId, 1, 2);
|
||||
finishRound(tournamentId, 9L);
|
||||
newRound(tournamentId, 2L);
|
||||
|
||||
startRound(tournamentId, 10L);
|
||||
playRound(tournamentId, 1, 3);
|
||||
// finishRound(2L, 10L);
|
||||
|
||||
}
|
||||
|
||||
private void addToTournament(Long tournamentId, Player player) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
TournamentPlayer tournamentPlayer = new TournamentPlayer();
|
||||
tournamentPlayer.setTournament(tournament);
|
||||
tournamentPlayer.setPlayer(player);
|
||||
tournament.getTournamentPlayers().add(tournamentPlayer);
|
||||
tournamentService.saveTournament(tournament);
|
||||
}
|
||||
|
||||
private void divideTournament(Long tournamentId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
tournamentDivideService.divide(tournament);
|
||||
}
|
||||
|
||||
private void drawTournament(Long tournamentId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
tournamentDrawService.draw(tournament);
|
||||
}
|
||||
|
||||
private void playRound(long tournamentId, int group, int round) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
for (var match : tournament.getEvents().get(0).getGroups().get(group).getRounds().get(round).getMatches()) {
|
||||
tournamentPlayService.startMatch(tournament, match.getId(), 1L);
|
||||
}
|
||||
|
||||
for (var match : tournament.getEvents().get(0).getGroups().get(group).getRounds().get(round).getMatches()) {
|
||||
tournament = tournamentService.findTournamentById(tournamentId);
|
||||
var resultDto = new ResultDto();
|
||||
resultDto.getGames().add(getRandomGame());
|
||||
resultDto.getGames().add(getRandomGame());
|
||||
resultDto.setMatchId(match.getId());
|
||||
tournamentPlayService.saveResult(tournament, match.getId(), resultDto);
|
||||
}
|
||||
}
|
||||
|
||||
private GameDto getRandomGame() {
|
||||
Random random = new Random();
|
||||
|
||||
var gameDto = new GameDto();
|
||||
gameDto.setScore1(21L);
|
||||
gameDto.setScore2(random.nextLong(19));
|
||||
|
||||
return gameDto;
|
||||
}
|
||||
|
||||
private void finishRound(long tournamentId, long roundId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
tournamentPlayService.finishRound(tournament, roundId);
|
||||
}
|
||||
|
||||
private void newRound(long tournamentId, long groupId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
tournamentPlayService.newRound(tournament, groupId);
|
||||
}
|
||||
|
||||
private void startRound(long tournamentId, long roundId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
tournamentPlayService.startRound(tournament, roundId);
|
||||
}
|
||||
|
||||
// private void saveTournament1() {
|
||||
// var tournament = new Tournament();
|
||||
// tournament.setName("Zwitsers Laddersysteem BC Holten 2023");
|
||||
// tournament.setDate(LocalDate.of(2023, Month.DECEMBER, 12));
|
||||
// tournament.setStatus(TournamentStatus.CLOSED);
|
||||
// tournamentService.saveTournament(tournament);
|
||||
// }
|
||||
|
||||
|
||||
private Long saveTournament() {
|
||||
var tournament = new Tournament();
|
||||
tournament.setName("Testtoernooi");
|
||||
tournament.setDate(LocalDate.of(2024, Month.DECEMBER, 14));
|
||||
tournament.setStatus(TournamentStatus.UPCOMING);
|
||||
tournament.setMaxEvents(2L);
|
||||
tournament.setCourts(9L);
|
||||
tournament.setCostsPerEvent(List.of(6f, 10f));
|
||||
tournamentService.saveTournament(tournament);
|
||||
return tournament.getId();
|
||||
}
|
||||
|
||||
private void registerForSingles(Long tournamentId, Player player) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
var registration = new Registration();
|
||||
registration.setPlayer(player);
|
||||
var event = tournament.getEventByType(player.getSex() == Sex.M ? EventType.HE : EventType.DE);
|
||||
registration.setPartner(null);
|
||||
registration.setTournament(tournament);
|
||||
registration.setEvent(event);
|
||||
if (event.getRegistrations() == null) event.setRegistrations(new ArrayList<>());
|
||||
event.getRegistrations().add(registration);
|
||||
// player.getRegistrations().add(registration);
|
||||
tournamentService.saveTournament(tournament);
|
||||
}
|
||||
|
||||
private void registerForDoubles(Long tournamentId, Player player, Player partner) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
var registration = new Registration();
|
||||
registration.setPlayer(player);
|
||||
registration.setPartner(partner);
|
||||
var event = tournament.getEventByType(
|
||||
player.getSex() == partner.getSex() ?
|
||||
(player.getSex() == Sex.M ? EventType.HD : EventType.DD) : EventType.GD);
|
||||
registration.setTournament(tournament);
|
||||
registration.setEvent(event);
|
||||
event.getRegistrations().add(registration);
|
||||
// player.getRegistrations().add(registration);
|
||||
tournamentService.saveTournament(tournament);
|
||||
}
|
||||
|
||||
// private Player savePlayer(String firstName, Sex sex) {
|
||||
// Random random = new Random();
|
||||
//
|
||||
// String[] lastNames = {
|
||||
// "Meedendorp", "Holstege", "Goedhart", "Zijlma", "Duursma", "Keizer", "Verschoor",
|
||||
// "Mulder", "Koers", "Duindam", "Castelein", "Coemans", "Huijbers", "Kelder",
|
||||
// "Stein", "Rakhorst", "Brugman", "Seinen", "Mayer", "Gijsman", "Kingma",
|
||||
// "Jansen", "Westerik", "Brehler", "Ebbers", "Lensink", "Lups", "Verboom"
|
||||
// };
|
||||
//
|
||||
// String[] clubs = {
|
||||
// "BC Holten", "BC Reflex", "ZBC", "WSV Apeldoorn", "BC IJsselstad", "Flits", "ELO United", "BC Kwiek"
|
||||
// };
|
||||
//
|
||||
// var player = new Player();
|
||||
// player.setFirstName(firstName);
|
||||
// player.setLastName(lastNames[random.nextInt(lastNames.length)]);
|
||||
// player.setClub(clubs[random.nextInt(clubs.length)]);
|
||||
// player.setSex(sex);
|
||||
// player.setBirthday(randomDate(LocalDate.of(1950, 1, 1), LocalDate.of(2010, 1, 1)));
|
||||
// player.setPhoneNumber("0612345678");
|
||||
// player.setEmail("aaaa@bbb.cc");
|
||||
// player.setStrength(getRandomStrength());
|
||||
//
|
||||
// playerService.savePlayer(player);
|
||||
// return player;
|
||||
// }
|
||||
*/
|
||||
|
||||
}
|
||||
184
src/main/java/nl/connectedit/swiss/controller/TournamentController.java
Executable file
184
src/main/java/nl/connectedit/swiss/controller/TournamentController.java
Executable file
@@ -0,0 +1,184 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.dto.ResultDto;
|
||||
import nl.connectedit.swiss.dto.TournamentDto;
|
||||
import nl.connectedit.swiss.dto.TournamentValidationDto;
|
||||
import nl.connectedit.swiss.mapper.TournamentMapper;
|
||||
import nl.connectedit.swiss.mapper.TournamentValidationMapper;
|
||||
import nl.connectedit.swiss.service.*;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentController {
|
||||
|
||||
private final TournamentService tournamentService;
|
||||
|
||||
private final TournamentMapper tournamentMapper;
|
||||
|
||||
private final TournamentValidationService tournamentValidationService;
|
||||
|
||||
private final TournamentValidationMapper tournamentValidationMapper;
|
||||
|
||||
private final TournamentDivideService tournamentDivideService;
|
||||
|
||||
private final TournamentDrawService tournamentDrawService;
|
||||
|
||||
private final TournamentPlayService tournamentPlayService;
|
||||
|
||||
@GetMapping("/tournaments")
|
||||
public ResponseEntity<List<TournamentDto>> getTournaments(@RequestParam(value = "status", required = false) TournamentStatus status) {
|
||||
List<Tournament> tournaments;
|
||||
|
||||
if (Objects.nonNull(status)) {
|
||||
tournaments = tournamentService.findAllTournamentsWithStatus(status);
|
||||
} else {
|
||||
tournaments = tournamentService.findAllTournaments();
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(tournaments
|
||||
.stream()
|
||||
.map(tournamentMapper::toDto)
|
||||
.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/tournaments/{id}")
|
||||
@Transactional
|
||||
public ResponseEntity<TournamentDto> getTournament(@PathVariable Long id) {
|
||||
var tournament = tournamentService.findTournamentById(id);
|
||||
|
||||
if (tournament == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournament));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments")
|
||||
public ResponseEntity<TournamentDto> createTournament(@RequestBody TournamentDto tournamentDto) {
|
||||
var tournament = tournamentMapper.toEntity(tournamentDto);
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentService.saveTournament(tournament)));
|
||||
}
|
||||
|
||||
@PutMapping("/tournaments/{id}")
|
||||
public ResponseEntity<TournamentDto> updateTournament(@PathVariable Long id, @RequestBody TournamentDto tournamentDto) {
|
||||
var newTournament = tournamentMapper.toEntity(tournamentDto);
|
||||
var tournament = tournamentService.updateTournament(id, newTournament);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournament));
|
||||
}
|
||||
|
||||
@GetMapping("/tournaments/{id}/validate")
|
||||
public ResponseEntity<TournamentValidationDto> validateTournament(@PathVariable Long id) {
|
||||
var tournament = tournamentService.findTournamentById(id);
|
||||
|
||||
var tournamentValidation = tournamentValidationService.validate(tournament);
|
||||
|
||||
return ResponseEntity.ok(tournamentValidationMapper.toDto(tournamentValidation));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{id}/divide")
|
||||
public ResponseEntity<TournamentDto> divideTournamentNew(@PathVariable Long id) {
|
||||
var tournament = tournamentService.findTournamentById(id);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentDivideService.divide(tournament)));
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/tournaments/{id}/divide/clear")
|
||||
public ResponseEntity<TournamentDto> clearTournamentDivision(@PathVariable Long id) {
|
||||
var tournament = tournamentService.findTournamentById(id);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentDivideService.clear(tournament)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{id}/draw")
|
||||
public ResponseEntity<TournamentDto> drawTournament(@PathVariable Long id) {
|
||||
var tournament = tournamentService.findTournamentById(id);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentDrawService.draw(tournament)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{id}/draw/clear")
|
||||
public ResponseEntity<TournamentDto> clearTournamentDraw(@PathVariable Long id) {
|
||||
var tournament = tournamentService.findTournamentById(id);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentDrawService.clear(tournament)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{tournamentId}/rounds/{roundId}/start")
|
||||
public ResponseEntity<TournamentDto> startRound(@PathVariable Long tournamentId, @PathVariable Long roundId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentPlayService.startRound(tournament, roundId)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{tournamentId}/rounds/{roundId}/finish")
|
||||
public ResponseEntity<TournamentDto> finishRound(@PathVariable Long tournamentId, @PathVariable Long roundId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentPlayService.finishRound(tournament, roundId)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{tournamentId}/groups/{groupId}/finish")
|
||||
public ResponseEntity<TournamentDto> finishGroup(@PathVariable Long tournamentId, @PathVariable Long groupId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentPlayService.finishGroup(tournament, groupId)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{tournamentId}/groups/{groupId}/new")
|
||||
public ResponseEntity<TournamentDto> newRound(@PathVariable Long tournamentId, @PathVariable Long groupId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentPlayService.newRound(tournament, groupId)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{tournamentId}/matches/{matchId}/start/{court}")
|
||||
public ResponseEntity<TournamentDto> startMatch(@PathVariable Long tournamentId, @PathVariable Long matchId, @PathVariable Long court) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentPlayService.startMatch(tournament, matchId, court)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{tournamentId}/matches/{matchId}/stop")
|
||||
public ResponseEntity<TournamentDto> stopMatch(@PathVariable Long tournamentId, @PathVariable Long matchId) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentPlayService.stopMatch(tournament, matchId)));
|
||||
}
|
||||
|
||||
@PostMapping("/tournaments/{tournamentId}/matches/{matchId}")
|
||||
public ResponseEntity<TournamentDto> saveResult(@PathVariable Long tournamentId, @PathVariable Long matchId, @RequestBody ResultDto resultDto) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
return ResponseEntity.ok(tournamentMapper.toDto(tournamentPlayService.saveResult(tournament, matchId, resultDto)));
|
||||
}
|
||||
|
||||
@PatchMapping("/tournaments/{tournamentId}/players/{playerId}/paid/{paid}")
|
||||
public ResponseEntity<Void> updatePaid(@PathVariable Long tournamentId, @PathVariable Long playerId, @PathVariable Boolean paid) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
tournamentPlayService.updatePaid(tournament, playerId, paid);
|
||||
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@PatchMapping("/tournaments/{tournamentId}/players/{playerId}/present/{present}")
|
||||
public ResponseEntity<Void> updatePresent(@PathVariable Long tournamentId, @PathVariable Long playerId, @PathVariable Boolean present) {
|
||||
var tournament = tournamentService.findTournamentById(tournamentId);
|
||||
|
||||
tournamentPlayService.updatePresent(tournament, playerId, present);
|
||||
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
||||
15
src/main/java/nl/connectedit/swiss/domain/EventDivision.java
Normal file
15
src/main/java/nl/connectedit/swiss/domain/EventDivision.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.connectedit.swiss.domain.entity.Group;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class EventDivision {
|
||||
|
||||
private Long eventId;
|
||||
|
||||
private List<Group> groups = new ArrayList<>();
|
||||
}
|
||||
20
src/main/java/nl/connectedit/swiss/domain/EventType.java
Normal file
20
src/main/java/nl/connectedit/swiss/domain/EventType.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum EventType {
|
||||
|
||||
HE("Herenenkel", false),
|
||||
DE("Damesenkel", false),
|
||||
HD("Herendubbel", true),
|
||||
DD("Damesdubbel", true),
|
||||
GD("Gemengd dubbel", true);
|
||||
|
||||
private final String text;
|
||||
|
||||
private final boolean isDoublesEvent;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class EventValidation {
|
||||
private Long eventId;
|
||||
|
||||
@Builder.Default
|
||||
private List<Validation> validations = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum PlayerStrength {
|
||||
D5(8),
|
||||
D6(6),
|
||||
D7(4),
|
||||
D8(3),
|
||||
D9(2),
|
||||
DR(1);
|
||||
|
||||
private final int coefficient;
|
||||
}
|
||||
10
src/main/java/nl/connectedit/swiss/domain/Sex.java
Normal file
10
src/main/java/nl/connectedit/swiss/domain/Sex.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Sex {
|
||||
|
||||
M, V
|
||||
|
||||
}
|
||||
8
src/main/java/nl/connectedit/swiss/domain/Status.java
Normal file
8
src/main/java/nl/connectedit/swiss/domain/Status.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
public enum Status {
|
||||
NOT_STARTED,
|
||||
READY_TO_PLAY,
|
||||
IN_PROGRESS,
|
||||
FINISHED
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class TournamentDivision {
|
||||
|
||||
private Long tournamentId;
|
||||
|
||||
private boolean divided;
|
||||
|
||||
private List<EventDivision> eventDivisions = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum TournamentStatus {
|
||||
UPCOMING("Nieuw"),
|
||||
DIVIDED("Ingedeeld"),
|
||||
DRAWN("Geloot"),
|
||||
ONGOING("Bezig"),
|
||||
CLOSED("Gesloten");
|
||||
|
||||
private final String text;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class TournamentValidation {
|
||||
|
||||
private Long tournamentId;
|
||||
|
||||
private List<Validation> validations;
|
||||
|
||||
private List<EventValidation> eventValidations;
|
||||
|
||||
public boolean hasErrors() {
|
||||
return !validations.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
19
src/main/java/nl/connectedit/swiss/domain/Validation.java
Normal file
19
src/main/java/nl/connectedit/swiss/domain/Validation.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package nl.connectedit.swiss.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Validation {
|
||||
public enum Severity {
|
||||
INFO, WARN, ERROR
|
||||
}
|
||||
private Severity severity;
|
||||
|
||||
private String message;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractEntity {
|
||||
|
||||
protected abstract Long getId();
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null) return false;
|
||||
Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
|
||||
Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
|
||||
if (thisEffectiveClass != oEffectiveClass) return false;
|
||||
AbstractEntity abstractEntity = (AbstractEntity) o;
|
||||
return getId() != null && Objects.equals(getId(), abstractEntity.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
62
src/main/java/nl/connectedit/swiss/domain/entity/Event.java
Normal file
62
src/main/java/nl/connectedit/swiss/domain/entity/Event.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import nl.connectedit.swiss.domain.EventType;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class Event extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Tournament tournament;
|
||||
|
||||
@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
|
||||
// @Builder.Default
|
||||
private List<Registration> registrations;// = new ArrayList<>();
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Status status;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private EventType type;
|
||||
|
||||
@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
|
||||
private List<Group> groups;// = new ArrayList<>();
|
||||
|
||||
public static List<Event> getBlankEventSet(Tournament tournament) {
|
||||
return Arrays.stream(EventType.values())
|
||||
.map(type -> Event
|
||||
.builder()
|
||||
.type(type)
|
||||
.status(Status.NOT_STARTED)
|
||||
.tournament(tournament)
|
||||
.build()
|
||||
)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
public void addRegistration(Registration registration) {
|
||||
this.registrations.add(registration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getType().getText();
|
||||
}
|
||||
}
|
||||
26
src/main/java/nl/connectedit/swiss/domain/entity/Game.java
Normal file
26
src/main/java/nl/connectedit/swiss/domain/entity/Game.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Game extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Match match;
|
||||
|
||||
private Long score1;
|
||||
|
||||
private Long score2;
|
||||
|
||||
}
|
||||
38
src/main/java/nl/connectedit/swiss/domain/entity/Group.java
Normal file
38
src/main/java/nl/connectedit/swiss/domain/entity/Group.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import nl.connectedit.swiss.domain.EventType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
|
||||
@Entity
|
||||
@Table(name = "eventgroup")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Group extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
private Event event;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Status status;
|
||||
|
||||
private EventType type;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Round> rounds;// = new ArrayList<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Team> teams;// = new ArrayList<>();
|
||||
|
||||
}
|
||||
49
src/main/java/nl/connectedit/swiss/domain/entity/Match.java
Normal file
49
src/main/java/nl/connectedit/swiss/domain/entity/Match.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import nl.connectedit.swiss.domain.EventType;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
public class Match extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private EventType type;
|
||||
|
||||
private Status status;
|
||||
|
||||
@ManyToOne
|
||||
private Round round;
|
||||
|
||||
@ManyToOne
|
||||
private Team team1;
|
||||
|
||||
@ManyToOne
|
||||
private Team team2;
|
||||
|
||||
private Boolean played;
|
||||
|
||||
private Long court;
|
||||
|
||||
@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
|
||||
private List<Game> games;// = new ArrayList<>();
|
||||
|
||||
private LocalDateTime startTime;
|
||||
|
||||
private LocalDateTime endTime;
|
||||
|
||||
}
|
||||
77
src/main/java/nl/connectedit/swiss/domain/entity/Player.java
Normal file
77
src/main/java/nl/connectedit/swiss/domain/entity/Player.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import nl.connectedit.swiss.domain.PlayerStrength;
|
||||
import nl.connectedit.swiss.domain.Sex;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.util.StringUtils.hasLength;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class Player extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
@NotEmpty
|
||||
private String firstName;
|
||||
|
||||
@Column
|
||||
private String middleName;
|
||||
|
||||
@Column(nullable = false)
|
||||
@NotEmpty
|
||||
private String lastName;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Sex sex;
|
||||
|
||||
@Column(nullable = false)
|
||||
@DateTimeFormat(pattern = "dd-MM-yyyy")
|
||||
private LocalDate birthday;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String phoneNumber;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String email;
|
||||
|
||||
@Column
|
||||
private String club;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PlayerStrength strength;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Registration> registrations;// = new ArrayList<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Registration> partnerRegistrations;// = new ArrayList<>();
|
||||
|
||||
public String getFullName() {
|
||||
return hasLength(middleName) ?
|
||||
String.join(" ", firstName, middleName, lastName) :
|
||||
String.join(" ", firstName, lastName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getFullName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
public class Registration extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Event event;
|
||||
|
||||
@ManyToOne
|
||||
private Tournament tournament;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "player_id")
|
||||
private Player player;
|
||||
|
||||
@Nullable
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "partner_id")
|
||||
private Player partner;
|
||||
|
||||
}
|
||||
39
src/main/java/nl/connectedit/swiss/domain/entity/Round.java
Normal file
39
src/main/java/nl/connectedit/swiss/domain/entity/Round.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
public class Round extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
private Group group;
|
||||
|
||||
private Status status;
|
||||
|
||||
@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
|
||||
private List<Match> matches;// = new ArrayList<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
|
||||
private List<Team> quit;// = new ArrayList<>();
|
||||
|
||||
@ManyToOne
|
||||
private Team drawnOut;
|
||||
|
||||
}
|
||||
34
src/main/java/nl/connectedit/swiss/domain/entity/Team.java
Normal file
34
src/main/java/nl/connectedit/swiss/domain/entity/Team.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
public class Team extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Group group;
|
||||
|
||||
@ManyToOne
|
||||
private Player player1;
|
||||
|
||||
@Nullable
|
||||
@ManyToOne
|
||||
private Player player2;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return player2 != null ? player1.toString() + " + " + player2.toString() : player1.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import nl.connectedit.swiss.domain.EventType;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
public class Tournament extends AbstractEntity {
|
||||
|
||||
public Tournament() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private LocalDate date;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private TournamentStatus status;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Event> events;// = new ArrayList<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<TournamentPlayer> tournamentPlayers;
|
||||
|
||||
private Long maxEvents;
|
||||
|
||||
@ElementCollection
|
||||
private List<Float> costsPerEvent;
|
||||
|
||||
private Long courts;
|
||||
|
||||
public void initialize() {
|
||||
this.events = new ArrayList<>();
|
||||
this.events.addAll(Event.getBlankEventSet(this));
|
||||
this.status = TournamentStatus.UPCOMING;
|
||||
}
|
||||
|
||||
public Event getEventByType(EventType type) {
|
||||
return events
|
||||
.stream()
|
||||
.filter(event -> event.getType().equals(type))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public List<Registration> getRegistrations() {
|
||||
return events
|
||||
.stream()
|
||||
.map(Event::getRegistrations)
|
||||
.flatMap(List::stream)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package nl.connectedit.swiss.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
@Getter
|
||||
@Setter
|
||||
public class TournamentPlayer extends AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Tournament tournament;
|
||||
|
||||
@ElementCollection
|
||||
private List<String> events;
|
||||
|
||||
@ManyToOne
|
||||
private Player player;
|
||||
|
||||
private boolean paid;
|
||||
|
||||
private boolean present;
|
||||
}
|
||||
4
src/main/java/nl/connectedit/swiss/dto/AbstractDto.java
Normal file
4
src/main/java/nl/connectedit/swiss/dto/AbstractDto.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
public class AbstractDto {
|
||||
}
|
||||
22
src/main/java/nl/connectedit/swiss/dto/EventDto.java
Normal file
22
src/main/java/nl/connectedit/swiss/dto/EventDto.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class EventDto extends AbstractDto {
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
private String status;
|
||||
|
||||
private boolean isDoublesEvent;
|
||||
|
||||
private List<RegistrationDto> registrations;
|
||||
|
||||
private List<GroupDto> groups;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class EventRegistrationDto extends AbstractDto {
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
private boolean isDoublesEvent;
|
||||
|
||||
private boolean registered;
|
||||
|
||||
private Long player;
|
||||
|
||||
private Long partner;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class EventValidationDto {
|
||||
|
||||
private Long eventId;
|
||||
|
||||
private List<ValidationDto> validations;
|
||||
}
|
||||
13
src/main/java/nl/connectedit/swiss/dto/GameDto.java
Normal file
13
src/main/java/nl/connectedit/swiss/dto/GameDto.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class GameDto extends AbstractDto {
|
||||
|
||||
private Long score1;
|
||||
|
||||
private Long score2;
|
||||
}
|
||||
26
src/main/java/nl/connectedit/swiss/dto/GroupDto.java
Normal file
26
src/main/java/nl/connectedit/swiss/dto/GroupDto.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class GroupDto extends AbstractDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String status;
|
||||
|
||||
private List<TeamDto> teams;
|
||||
|
||||
private List<RoundDto> rounds;
|
||||
|
||||
private StandingsDto standings;
|
||||
|
||||
}
|
||||
32
src/main/java/nl/connectedit/swiss/dto/MatchDto.java
Normal file
32
src/main/java/nl/connectedit/swiss/dto/MatchDto.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class MatchDto extends AbstractDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
private String status;
|
||||
|
||||
private TeamDto team1;
|
||||
|
||||
private TeamDto team2;
|
||||
|
||||
private Boolean played;
|
||||
|
||||
private List<GameDto> games;
|
||||
|
||||
private LocalDateTime startTime;
|
||||
|
||||
private LocalDateTime endTime;
|
||||
|
||||
private Long court;
|
||||
}
|
||||
34
src/main/java/nl/connectedit/swiss/dto/PlayerDto.java
Normal file
34
src/main/java/nl/connectedit/swiss/dto/PlayerDto.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PlayerDto extends AbstractDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String middleName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
private String sex;
|
||||
|
||||
@DateTimeFormat(pattern = "dd-MM-yyyy")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
|
||||
private String birthday;
|
||||
|
||||
private String phoneNumber;
|
||||
|
||||
private String email;
|
||||
|
||||
private String club;
|
||||
|
||||
private String strength;
|
||||
|
||||
}
|
||||
15
src/main/java/nl/connectedit/swiss/dto/RegistrationDto.java
Normal file
15
src/main/java/nl/connectedit/swiss/dto/RegistrationDto.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class RegistrationDto extends AbstractDto {
|
||||
private Long id;
|
||||
|
||||
private PlayerDto player;
|
||||
|
||||
private PlayerDto partner;
|
||||
}
|
||||
|
||||
15
src/main/java/nl/connectedit/swiss/dto/ResultDto.java
Normal file
15
src/main/java/nl/connectedit/swiss/dto/ResultDto.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ResultDto extends AbstractDto {
|
||||
|
||||
private Long matchId;
|
||||
|
||||
private List<GameDto> games = new ArrayList<>();
|
||||
}
|
||||
26
src/main/java/nl/connectedit/swiss/dto/RoundDto.java
Normal file
26
src/main/java/nl/connectedit/swiss/dto/RoundDto.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class RoundDto extends AbstractDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private List<MatchDto> matches;
|
||||
|
||||
private String status;
|
||||
|
||||
private List<TeamDto> quit;
|
||||
|
||||
private TeamDto drawnOut;
|
||||
|
||||
private StandingsDto standings;
|
||||
|
||||
}
|
||||
13
src/main/java/nl/connectedit/swiss/dto/StandingsDto.java
Normal file
13
src/main/java/nl/connectedit/swiss/dto/StandingsDto.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class StandingsDto {
|
||||
|
||||
private List<StandingsEntryDto> entries = new ArrayList<>();
|
||||
}
|
||||
69
src/main/java/nl/connectedit/swiss/dto/StandingsEntry.java
Normal file
69
src/main/java/nl/connectedit/swiss/dto/StandingsEntry.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import java.util.Comparator;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import nl.connectedit.swiss.domain.entity.Team;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class StandingsEntry {
|
||||
|
||||
public StandingsEntry(Team team) {
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
private Long position;
|
||||
|
||||
private Team team;
|
||||
|
||||
private Long played = 0L;
|
||||
|
||||
private Long won = 0L;
|
||||
|
||||
private Long lost = 0L;
|
||||
|
||||
private Long points = 0L;
|
||||
|
||||
private Long gamesWon = 0L;
|
||||
|
||||
private Long gamesLost = 0L;
|
||||
|
||||
private Long pointsWon = 0L;
|
||||
|
||||
private Long pointsLost = 0L;
|
||||
|
||||
public static int compare(StandingsEntry s1, StandingsEntry s2) {
|
||||
var pointsPerMatchS1 = safeDivide(s1.points, s1.played);
|
||||
var pointsPerMatchS2 = safeDivide(s2.points, s2.played);
|
||||
if (pointsPerMatchS1 > pointsPerMatchS2) {
|
||||
return -1;
|
||||
} else if (pointsPerMatchS1 < pointsPerMatchS2) {
|
||||
return 1;
|
||||
} else {
|
||||
if (s1.played < s2.played) {
|
||||
return -1;
|
||||
} else if (s1.played > s2.played) {
|
||||
return 1;
|
||||
} else {
|
||||
var gamesPerMatchS1 = safeDivide(s1.gamesWon - s1.gamesLost, s1.played);
|
||||
var gamesPerMatchS2 = safeDivide(s2.gamesWon - s2.gamesLost, s2.played);
|
||||
if (gamesPerMatchS1 > gamesPerMatchS2) {
|
||||
return -1;
|
||||
} else if (gamesPerMatchS1 < gamesPerMatchS2) {
|
||||
return 1;
|
||||
} else {
|
||||
var ptsPerMatchS1 = safeDivide(s1.pointsWon - s1.pointsLost, s1.played);
|
||||
var ptsPerMatchS2 = safeDivide(s2.pointsWon - s2.pointsLost, s2.played);
|
||||
return Double.compare(ptsPerMatchS2, ptsPerMatchS1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double safeDivide(Long a, Long b) {
|
||||
return (a == 0 && b == 0) ? 0 : (double) a / b;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class StandingsEntryDto {
|
||||
|
||||
private Long position;
|
||||
|
||||
private TeamDto team;
|
||||
|
||||
private Long played;
|
||||
|
||||
private Long won;
|
||||
|
||||
private Long lost;
|
||||
|
||||
private Long points;
|
||||
|
||||
private Long gamesWon;
|
||||
|
||||
private Long gamesLost;
|
||||
|
||||
private Long pointsWon;
|
||||
|
||||
private Long pointsLost;
|
||||
|
||||
}
|
||||
13
src/main/java/nl/connectedit/swiss/dto/TeamDto.java
Normal file
13
src/main/java/nl/connectedit/swiss/dto/TeamDto.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TeamDto extends AbstractDto {
|
||||
|
||||
private PlayerDto player1;
|
||||
|
||||
private PlayerDto player2;
|
||||
}
|
||||
32
src/main/java/nl/connectedit/swiss/dto/TournamentDto.java
Normal file
32
src/main/java/nl/connectedit/swiss/dto/TournamentDto.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TournamentDto extends AbstractDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
|
||||
private String date;
|
||||
|
||||
private String status;
|
||||
|
||||
private List<EventDto> events;
|
||||
|
||||
private List<TournamentPlayerDto> tournamentPlayers;
|
||||
|
||||
private Long maxEvents;
|
||||
|
||||
private List<Float> costsPerEvent;
|
||||
|
||||
private Long courts;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TournamentPlayerDto extends AbstractDto {
|
||||
|
||||
private Long playerId;
|
||||
|
||||
private String name;
|
||||
|
||||
private List<String> events;
|
||||
|
||||
private Boolean paid;
|
||||
|
||||
private Boolean present;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TournamentRegistrationDto extends AbstractDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Boolean editable;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
|
||||
private String date;
|
||||
|
||||
private String status;
|
||||
|
||||
private List<EventRegistrationDto> events;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import nl.connectedit.swiss.domain.Validation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TournamentValidationDto extends AbstractDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
private List<Validation> validations;
|
||||
|
||||
private List<EventValidationDto> eventValidations;
|
||||
}
|
||||
|
||||
11
src/main/java/nl/connectedit/swiss/dto/ValidationDto.java
Normal file
11
src/main/java/nl/connectedit/swiss/dto/ValidationDto.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package nl.connectedit.swiss.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ValidationDto extends AbstractDto {
|
||||
private String severity;
|
||||
private String message;
|
||||
}
|
||||
8
src/main/java/nl/connectedit/swiss/mapper/DtoMapper.java
Normal file
8
src/main/java/nl/connectedit/swiss/mapper/DtoMapper.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.AbstractEntity;
|
||||
import nl.connectedit.swiss.dto.AbstractDto;
|
||||
|
||||
public interface DtoMapper<E extends AbstractEntity, D extends AbstractDto> {
|
||||
D toDto(E entity);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.AbstractEntity;
|
||||
import nl.connectedit.swiss.dto.AbstractDto;
|
||||
|
||||
public interface EntityMapper<D extends AbstractDto, E extends AbstractEntity> {
|
||||
E toEntity(D dto);
|
||||
}
|
||||
66
src/main/java/nl/connectedit/swiss/mapper/EventMapper.java
Normal file
66
src/main/java/nl/connectedit/swiss/mapper/EventMapper.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
import nl.connectedit.swiss.domain.entity.Event;
|
||||
import nl.connectedit.swiss.domain.EventType;
|
||||
import nl.connectedit.swiss.dto.EventDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class EventMapper implements DtoMapper<Event, EventDto>, EntityMapper<EventDto, Event> {
|
||||
|
||||
private final RegistrationMapper registrationMapper;
|
||||
|
||||
private final GroupMapper groupMapper;
|
||||
|
||||
@Override
|
||||
public Event toEntity(EventDto eventDto) {
|
||||
Event event = new Event();
|
||||
event.setId(eventDto.getId());
|
||||
event.setType(
|
||||
Arrays.stream(EventType.values())
|
||||
.filter(ts -> ts.getText().equals(eventDto.getType()))
|
||||
.findFirst()
|
||||
.orElse(null)
|
||||
);
|
||||
event.setStatus(Status.valueOf(eventDto.getStatus()));
|
||||
event.setRegistrations(
|
||||
eventDto.getRegistrations()
|
||||
.stream()
|
||||
.map(registrationMapper::toEntity)
|
||||
.toList()
|
||||
);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventDto toDto(Event event) {
|
||||
EventDto eventDto = new EventDto();
|
||||
eventDto.setId(event.getId());
|
||||
eventDto.setType(event.getType().name());
|
||||
eventDto.setStatus(event.getStatus().name());
|
||||
eventDto.setDoublesEvent(event.getType().isDoublesEvent());
|
||||
if (event.getRegistrations() != null) {
|
||||
eventDto.setRegistrations(
|
||||
event.getRegistrations()
|
||||
.stream()
|
||||
.map(registrationMapper::toDto)
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
if (event.getGroups() != null) {
|
||||
eventDto.setGroups(
|
||||
event.getGroups()
|
||||
.stream()
|
||||
.map(groupMapper::toDto)
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
return eventDto;
|
||||
}
|
||||
}
|
||||
18
src/main/java/nl/connectedit/swiss/mapper/GameMapper.java
Normal file
18
src/main/java/nl/connectedit/swiss/mapper/GameMapper.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.Game;
|
||||
import nl.connectedit.swiss.dto.GameDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class GameMapper implements DtoMapper<Game, GameDto> {
|
||||
|
||||
@Override
|
||||
public GameDto toDto(Game game) {
|
||||
var gameDto = new GameDto();
|
||||
gameDto.setScore1(game.getScore1());
|
||||
gameDto.setScore2(game.getScore2());
|
||||
|
||||
return gameDto;
|
||||
}
|
||||
}
|
||||
55
src/main/java/nl/connectedit/swiss/mapper/GroupMapper.java
Normal file
55
src/main/java/nl/connectedit/swiss/mapper/GroupMapper.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
import nl.connectedit.swiss.domain.entity.Group;
|
||||
import nl.connectedit.swiss.domain.entity.Round;
|
||||
import nl.connectedit.swiss.dto.GroupDto;
|
||||
import nl.connectedit.swiss.dto.RoundDto;
|
||||
import nl.connectedit.swiss.service.StandingsService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class GroupMapper implements DtoMapper<Group, GroupDto> {
|
||||
|
||||
private final TeamMapper teamMapper;
|
||||
|
||||
private final RoundMapper roundMapper;
|
||||
|
||||
private final StandingsService standingsService;
|
||||
|
||||
private final StandingsMapper standingsMapper;
|
||||
|
||||
@Override
|
||||
public GroupDto toDto(Group group) {
|
||||
var groupDto = new GroupDto();
|
||||
groupDto.setId(group.getId());
|
||||
groupDto.setName(group.getName());
|
||||
groupDto.setType(group.getType().name());
|
||||
groupDto.setStatus(group.getStatus().name());
|
||||
groupDto.setTeams(
|
||||
group.getTeams()
|
||||
.stream()
|
||||
.map(teamMapper::toDto)
|
||||
.toList());
|
||||
|
||||
var standingsGroup = new ArrayList<Round>();
|
||||
var rounds = new ArrayList<RoundDto>();
|
||||
if (group.getRounds() != null) {
|
||||
for (var round : group.getRounds()) {
|
||||
if (round.getStatus() == Status.FINISHED) {
|
||||
standingsGroup.add(round);
|
||||
}
|
||||
rounds.add(roundMapper.toDto(round, standingsGroup, group.getTeams()));
|
||||
}
|
||||
}
|
||||
groupDto.setRounds(rounds);
|
||||
|
||||
var standings = standingsService.getStandings(group.getRounds(), group.getTeams());
|
||||
groupDto.setStandings(standingsMapper.toDto(standings));
|
||||
|
||||
return groupDto;
|
||||
}
|
||||
}
|
||||
39
src/main/java/nl/connectedit/swiss/mapper/MatchMapper.java
Normal file
39
src/main/java/nl/connectedit/swiss/mapper/MatchMapper.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Match;
|
||||
import nl.connectedit.swiss.dto.MatchDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MatchMapper implements DtoMapper<Match, MatchDto> {
|
||||
|
||||
private final TeamMapper teamMapper;
|
||||
|
||||
private final GameMapper gameMapper;
|
||||
|
||||
@Override
|
||||
public MatchDto toDto(Match match) {
|
||||
var matchDto = new MatchDto();
|
||||
|
||||
matchDto.setId(match.getId());
|
||||
matchDto.setType(match.getType().name());
|
||||
matchDto.setStatus(match.getStatus().name());
|
||||
matchDto.setTeam1(teamMapper.toDto(match.getTeam1()));
|
||||
matchDto.setTeam2(teamMapper.toDto(match.getTeam2()));
|
||||
matchDto.setStartTime(match.getStartTime());
|
||||
matchDto.setEndTime(match.getEndTime());
|
||||
matchDto.setCourt(match.getCourt());
|
||||
|
||||
if (match.getGames() != null) {
|
||||
matchDto.setGames(
|
||||
match.getGames()
|
||||
.stream()
|
||||
.map(gameMapper::toDto)
|
||||
.toList());
|
||||
}
|
||||
|
||||
return matchDto;
|
||||
}
|
||||
}
|
||||
57
src/main/java/nl/connectedit/swiss/mapper/PlayerMapper.java
Normal file
57
src/main/java/nl/connectedit/swiss/mapper/PlayerMapper.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.domain.PlayerStrength;
|
||||
import nl.connectedit.swiss.domain.Sex;
|
||||
import nl.connectedit.swiss.dto.PlayerDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Objects;
|
||||
|
||||
@Component
|
||||
public class PlayerMapper implements DtoMapper<Player, PlayerDto>, EntityMapper<PlayerDto, Player> {
|
||||
|
||||
@Override
|
||||
public Player toEntity(PlayerDto playerDto) {
|
||||
Objects.requireNonNull(playerDto.getFirstName(), "Voornaam is verplicht");
|
||||
Objects.requireNonNull(playerDto.getLastName(), "Achternaam is verplicht");
|
||||
Objects.requireNonNull(playerDto.getSex(), "Geslacht is verplicht");
|
||||
Objects.requireNonNull(playerDto.getPhoneNumber(), "Telefoon is verplicht");
|
||||
Objects.requireNonNull(playerDto.getEmail(), "Emailadres is verplicht");
|
||||
Objects.requireNonNull(playerDto.getBirthday(), "Geboortedatum is verplicht");
|
||||
Objects.requireNonNull(playerDto.getStrength(), "Speelsterkte is verplicht");
|
||||
|
||||
Player player = new Player();
|
||||
player.setId(playerDto.getId());
|
||||
player.setFirstName(playerDto.getFirstName());
|
||||
player.setMiddleName(playerDto.getMiddleName());
|
||||
player.setLastName(playerDto.getLastName());
|
||||
player.setSex(Sex.valueOf(playerDto.getSex()));
|
||||
player.setBirthday(LocalDate.parse(playerDto.getBirthday(), DateTimeFormatter.ofPattern("dd-MM-yyyy")));
|
||||
player.setPhoneNumber(playerDto.getPhoneNumber());
|
||||
player.setEmail(playerDto.getEmail());
|
||||
player.setClub(playerDto.getClub());
|
||||
player.setStrength(PlayerStrength.valueOf(playerDto.getStrength()));
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerDto toDto(Player player) {
|
||||
PlayerDto playerDto = new PlayerDto();
|
||||
playerDto.setId(player.getId());
|
||||
playerDto.setFirstName(player.getFirstName());
|
||||
playerDto.setMiddleName(player.getMiddleName());
|
||||
playerDto.setLastName(player.getLastName());
|
||||
playerDto.setSex(player.getSex().name());
|
||||
playerDto.setBirthday(player.getBirthday().format(DateTimeFormatter.ofPattern("dd-MM-yyyy")));
|
||||
playerDto.setPhoneNumber(player.getPhoneNumber());
|
||||
playerDto.setEmail(player.getEmail());
|
||||
playerDto.setClub(player.getClub());
|
||||
playerDto.setStrength(player.getStrength().name());
|
||||
|
||||
return playerDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Registration;
|
||||
import nl.connectedit.swiss.dto.RegistrationDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RegistrationMapper implements DtoMapper<Registration, RegistrationDto>, EntityMapper<RegistrationDto, Registration> {
|
||||
|
||||
private final PlayerMapper playerMapper;
|
||||
|
||||
@Override
|
||||
public Registration toEntity(RegistrationDto registrationDto) {
|
||||
Registration registration = new Registration();
|
||||
registration.setId(registrationDto.getId());
|
||||
registration.setPlayer(playerMapper.toEntity(registrationDto.getPlayer()));
|
||||
if (registrationDto.getPartner() != null) {
|
||||
registration.setPartner(playerMapper.toEntity(registrationDto.getPartner()));
|
||||
}
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationDto toDto(Registration registration) {
|
||||
RegistrationDto registrationDto = new RegistrationDto();
|
||||
registrationDto.setId(registration.getId());
|
||||
// registrationDto.setTournament(registration.getEvent().getTournament().getId());
|
||||
registrationDto.setPlayer(playerMapper.toDto(registration.getPlayer()));
|
||||
if (registration.getPartner() != null) {
|
||||
registrationDto.setPartner(playerMapper.toDto(registration.getPartner()));
|
||||
}
|
||||
return registrationDto;
|
||||
}
|
||||
}
|
||||
53
src/main/java/nl/connectedit/swiss/mapper/RoundMapper.java
Normal file
53
src/main/java/nl/connectedit/swiss/mapper/RoundMapper.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Group;
|
||||
import nl.connectedit.swiss.domain.entity.Round;
|
||||
import nl.connectedit.swiss.domain.entity.Team;
|
||||
import nl.connectedit.swiss.dto.RoundDto;
|
||||
import nl.connectedit.swiss.service.StandingsService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RoundMapper {
|
||||
|
||||
private final MatchMapper matchMapper;
|
||||
|
||||
private final TeamMapper teamMapper;
|
||||
|
||||
private final StandingsService standingsService;
|
||||
|
||||
private final StandingsMapper standingsMapper;
|
||||
|
||||
public RoundDto toDto(Round round, List<Round> roundsForStandings, List<Team> teamsForStandings) {
|
||||
var roundDto = new RoundDto();
|
||||
roundDto.setId(round.getId());
|
||||
roundDto.setName(round.getName());
|
||||
roundDto.setMatches(
|
||||
round.getMatches()
|
||||
.stream()
|
||||
.map(matchMapper::toDto)
|
||||
.toList());
|
||||
roundDto.setStatus(round.getStatus().name());
|
||||
if (round.getQuit() != null) {
|
||||
roundDto.setQuit(
|
||||
round.getQuit()
|
||||
.stream()
|
||||
.map(teamMapper::toDto)
|
||||
.toList());
|
||||
}
|
||||
if (round.getDrawnOut() != null) {
|
||||
roundDto.setDrawnOut(teamMapper.toDto(round.getDrawnOut()));
|
||||
}
|
||||
|
||||
var standings = standingsService.getStandings(roundsForStandings, teamsForStandings);
|
||||
roundDto.setStandings(standingsMapper.toDto(standings));
|
||||
|
||||
return roundDto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.dto.StandingsDto;
|
||||
import nl.connectedit.swiss.dto.StandingsEntry;
|
||||
import nl.connectedit.swiss.dto.StandingsEntryDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class StandingsMapper {
|
||||
|
||||
private final TeamMapper teamMapper;
|
||||
|
||||
public StandingsDto toDto(List<StandingsEntry> standings) {
|
||||
var standingsDto = new StandingsDto();
|
||||
Long position = 1L;
|
||||
for (Iterator<StandingsEntry> i = standings.iterator(); i.hasNext(); position++ ) {
|
||||
standingsDto.getEntries().add(toDto(i.next(), position));
|
||||
}
|
||||
|
||||
return standingsDto;
|
||||
}
|
||||
|
||||
private StandingsEntryDto toDto(StandingsEntry standingsEntry, Long position) {
|
||||
var standingsEntryDto = new StandingsEntryDto();
|
||||
standingsEntryDto.setPosition(position);
|
||||
standingsEntryDto.setTeam(teamMapper.toDto(standingsEntry.getTeam()));
|
||||
standingsEntryDto.setPlayed(standingsEntry.getPlayed());
|
||||
standingsEntryDto.setWon(standingsEntry.getWon());
|
||||
standingsEntryDto.setLost(standingsEntry.getLost());
|
||||
standingsEntryDto.setPoints(standingsEntry.getPoints());
|
||||
standingsEntryDto.setGamesWon(standingsEntry.getGamesWon());
|
||||
standingsEntryDto.setGamesLost(standingsEntry.getGamesLost());
|
||||
standingsEntryDto.setPointsWon(standingsEntry.getPointsWon());
|
||||
standingsEntryDto.setPointsLost(standingsEntry.getPointsLost());
|
||||
|
||||
return standingsEntryDto;
|
||||
}
|
||||
}
|
||||
25
src/main/java/nl/connectedit/swiss/mapper/TeamMapper.java
Normal file
25
src/main/java/nl/connectedit/swiss/mapper/TeamMapper.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Team;
|
||||
import nl.connectedit.swiss.dto.TeamDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TeamMapper implements DtoMapper<Team, TeamDto> {
|
||||
|
||||
private final PlayerMapper playerMapper;
|
||||
|
||||
@Override
|
||||
public TeamDto toDto(Team team) {
|
||||
var teamDto = new TeamDto();
|
||||
teamDto.setPlayer1(playerMapper.toDto(team.getPlayer1()));
|
||||
|
||||
if (team.getPlayer2() != null) {
|
||||
teamDto.setPlayer2(playerMapper.toDto(team.getPlayer2()));
|
||||
}
|
||||
|
||||
return teamDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.domain.entity.TournamentPlayer;
|
||||
import nl.connectedit.swiss.dto.TournamentDto;
|
||||
import nl.connectedit.swiss.dto.TournamentPlayerDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentMapper implements DtoMapper<Tournament, TournamentDto>, EntityMapper<TournamentDto, Tournament> {
|
||||
|
||||
private final EventMapper eventMapper;
|
||||
|
||||
private final TournamentPlayerMapper tournamentPlayerMapper;
|
||||
|
||||
@Override
|
||||
public Tournament toEntity(TournamentDto tournamentDto) {
|
||||
Tournament tournament = new Tournament();
|
||||
tournament.setId(tournamentDto.getId());
|
||||
tournament.setName(tournamentDto.getName());
|
||||
tournament.setDate(LocalDate.parse(tournamentDto.getDate(), DateTimeFormatter.ofPattern("dd-MM-yyyy")));
|
||||
tournament.setStatus(
|
||||
Arrays.stream(TournamentStatus.values())
|
||||
.filter(ts -> ts.getText().equals(tournamentDto.getStatus()))
|
||||
.findFirst()
|
||||
.orElse(TournamentStatus.UPCOMING)
|
||||
);
|
||||
tournament.setMaxEvents(tournamentDto.getMaxEvents());
|
||||
tournament.setCostsPerEvent(tournamentDto.getCostsPerEvent());
|
||||
tournament.setCourts(tournamentDto.getCourts());
|
||||
|
||||
return tournament;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TournamentDto toDto(Tournament tournament) {
|
||||
TournamentDto tournamentDto = new TournamentDto();
|
||||
tournamentDto.setId(tournament.getId());
|
||||
tournamentDto.setName(tournament.getName());
|
||||
tournamentDto.setDate(tournament.getDate().format(DateTimeFormatter.ofPattern("dd-MM-yyyy")));
|
||||
tournamentDto.setStatus(tournament.getStatus().name());
|
||||
tournamentDto.setEvents(
|
||||
tournament.getEvents()
|
||||
.stream()
|
||||
.map(eventMapper::toDto)
|
||||
.toList()
|
||||
);
|
||||
|
||||
if (tournament.getTournamentPlayers() != null) {
|
||||
var tournamentPlayers = tournament.getTournamentPlayers();
|
||||
|
||||
tournamentPlayers.sort(Comparator.comparing((TournamentPlayer tournamentPlayer) -> tournamentPlayer.getPlayer().getLastName())
|
||||
.thenComparing((TournamentPlayer tournamentPlayer) -> tournamentPlayer.getPlayer().getFirstName()));
|
||||
|
||||
tournamentDto.setTournamentPlayers(tournamentPlayers
|
||||
.stream()
|
||||
.map(tournamentPlayerMapper::toDto)
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
tournamentDto.setMaxEvents(tournament.getMaxEvents() == null ? 2L : tournament.getMaxEvents());
|
||||
|
||||
if (tournament.getCostsPerEvent() == null || tournament.getCostsPerEvent().isEmpty()) {
|
||||
tournamentDto.setCostsPerEvent(List.of(0f, 0f, 0f));
|
||||
} else {
|
||||
tournamentDto.setCostsPerEvent(tournament.getCostsPerEvent());
|
||||
}
|
||||
|
||||
tournamentDto.setCourts(tournament.getCourts() == null ? 1L : tournament.getCourts());
|
||||
|
||||
return tournamentDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Team;
|
||||
import nl.connectedit.swiss.domain.entity.TournamentPlayer;
|
||||
import nl.connectedit.swiss.dto.TeamDto;
|
||||
import nl.connectedit.swiss.dto.TournamentPlayerDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentPlayerMapper implements DtoMapper<TournamentPlayer, TournamentPlayerDto> {
|
||||
|
||||
private final PlayerMapper playerMapper;
|
||||
|
||||
@Override
|
||||
public TournamentPlayerDto toDto(TournamentPlayer tournamentPlayer) {
|
||||
var tournamentPlayerDto = new TournamentPlayerDto();
|
||||
tournamentPlayerDto.setPlayerId(tournamentPlayer.getPlayer().getId());
|
||||
tournamentPlayerDto.setName(tournamentPlayer.getPlayer().getFullName());
|
||||
tournamentPlayerDto.setEvents(new ArrayList<>(tournamentPlayer.getEvents()));
|
||||
tournamentPlayerDto.setPaid(tournamentPlayer.isPaid());
|
||||
tournamentPlayerDto.setPresent(tournamentPlayer.isPresent());
|
||||
|
||||
return tournamentPlayerDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.domain.entity.Event;
|
||||
import nl.connectedit.swiss.domain.EventType;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.domain.Sex;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.dto.EventRegistrationDto;
|
||||
import nl.connectedit.swiss.dto.TournamentRegistrationDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentPlayerRegistrationMapper {
|
||||
|
||||
public List<TournamentRegistrationDto> mapToDto(List<Tournament> tournaments, Player player) {
|
||||
return tournaments.stream()
|
||||
.map(tournament -> this.mapToTournamentRegistrationDto(tournament, player))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public TournamentRegistrationDto mapToTournamentRegistrationDto(Tournament tournament, Player player) {
|
||||
TournamentRegistrationDto tournamentRegistrationDto = new TournamentRegistrationDto();
|
||||
tournamentRegistrationDto.setId(tournament.getId());
|
||||
tournamentRegistrationDto.setName(tournament.getName());
|
||||
tournamentRegistrationDto.setEditable(tournament.getStatus() == TournamentStatus.UPCOMING);
|
||||
tournamentRegistrationDto.setDate(tournament.getDate().format(DateTimeFormatter.ofPattern("dd-MM-yyyy")));
|
||||
tournamentRegistrationDto.setStatus(tournament.getStatus().name());
|
||||
tournamentRegistrationDto.setEvents(
|
||||
tournament.getEvents()
|
||||
.stream()
|
||||
.filter(event -> isRelevant(event, player))
|
||||
.map(event -> this.mapToEventRegistrationDto(event, player))
|
||||
.toList()
|
||||
);
|
||||
|
||||
return tournamentRegistrationDto;
|
||||
}
|
||||
|
||||
private boolean isRelevant(Event event, Player player) {
|
||||
if (player.getSex() == Sex.M) {
|
||||
return switch(event.getType()) {
|
||||
case EventType.HE, EventType.HD, EventType.GD -> true;
|
||||
default -> false;
|
||||
};
|
||||
} else {
|
||||
return switch(event.getType()) {
|
||||
case EventType.DE, EventType.DD, EventType.GD -> true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private EventRegistrationDto mapToEventRegistrationDto(Event event, Player player) {
|
||||
EventRegistrationDto eventRegistrationDto = new EventRegistrationDto();
|
||||
eventRegistrationDto.setId(event.getId());
|
||||
eventRegistrationDto.setType(event.getType().name());
|
||||
eventRegistrationDto.setDoublesEvent(event.getType().isDoublesEvent());
|
||||
for (var registration : event.getRegistrations()) {
|
||||
if (registration.getPlayer().getId().equals(player.getId())) {
|
||||
eventRegistrationDto.setRegistered(true);
|
||||
eventRegistrationDto.setPlayer(registration.getPlayer().getId());
|
||||
if (registration.getPartner() != null) {
|
||||
eventRegistrationDto.setPartner(registration.getPartner().getId());
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
eventRegistrationDto.setRegistered(false);
|
||||
}
|
||||
}
|
||||
return eventRegistrationDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package nl.connectedit.swiss.mapper;
|
||||
|
||||
import nl.connectedit.swiss.domain.Validation;
|
||||
import nl.connectedit.swiss.domain.EventValidation;
|
||||
import nl.connectedit.swiss.domain.TournamentValidation;
|
||||
import nl.connectedit.swiss.dto.EventValidationDto;
|
||||
import nl.connectedit.swiss.dto.TournamentValidationDto;
|
||||
import nl.connectedit.swiss.dto.ValidationDto;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TournamentValidationMapper {
|
||||
|
||||
public TournamentValidationDto toDto(TournamentValidation tournamentValidation) {
|
||||
var tournamentValidationDto = new TournamentValidationDto();
|
||||
tournamentValidationDto.setId(tournamentValidation.getTournamentId());
|
||||
tournamentValidationDto.setValidations(tournamentValidation.getValidations());
|
||||
tournamentValidationDto.setEventValidations(
|
||||
tournamentValidation.getEventValidations()
|
||||
.stream()
|
||||
.map(this::toEventValidationDto)
|
||||
.toList()
|
||||
);
|
||||
return tournamentValidationDto;
|
||||
}
|
||||
|
||||
private EventValidationDto toEventValidationDto(EventValidation eventValidation) {
|
||||
var eventValidationDto = new EventValidationDto();
|
||||
eventValidationDto.setEventId(eventValidation.getEventId());
|
||||
eventValidationDto.setValidations(
|
||||
eventValidation.getValidations()
|
||||
.stream()
|
||||
.map(this::toValidationDto)
|
||||
.toList()
|
||||
);
|
||||
return eventValidationDto;
|
||||
}
|
||||
|
||||
private ValidationDto toValidationDto(Validation validation) {
|
||||
var validationDto = new ValidationDto();
|
||||
validationDto.setSeverity(validation.getSeverity().name());
|
||||
validationDto.setMessage(validation.getMessage());
|
||||
return validationDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package nl.connectedit.swiss.repository;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface PlayerRepository extends JpaRepository<Player, Long> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package nl.connectedit.swiss.repository;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.Registration;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RegistrationRepository extends JpaRepository<Registration, Long> {
|
||||
|
||||
@Query("""
|
||||
select r from Registration r
|
||||
where r.player.id = :playerId
|
||||
""")
|
||||
List<Registration> findRegistrationsForPlayer(@Param("playerId") Long playerId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package nl.connectedit.swiss.repository;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TournamentRepository extends JpaRepository<Tournament, Long> {
|
||||
|
||||
List<Tournament> findAllByStatus(TournamentStatus status);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.repository.PlayerRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PlayerService {
|
||||
|
||||
private final PlayerRepository playerRepository;
|
||||
|
||||
public Player savePlayer(Player player) {
|
||||
return playerRepository.save(player);
|
||||
}
|
||||
|
||||
public List<Player> findAllPlayers() {
|
||||
return playerRepository.findAll();
|
||||
}
|
||||
|
||||
public Player findPlayerById(Long id) {
|
||||
return playerRepository.getReferenceById(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.domain.entity.Registration;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.dto.EventRegistrationDto;
|
||||
import nl.connectedit.swiss.repository.RegistrationRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RegistrationService {
|
||||
|
||||
private final TournamentService tournamentService;
|
||||
|
||||
private final PlayerService playerService;
|
||||
|
||||
public void updateOrAddRegistrations(EventRegistrationDto eventRegistration, Tournament tournament, Player player) {
|
||||
var event = tournament.getEvents().stream().filter(e -> e.getId().equals(eventRegistration.getId())).findFirst().orElseThrow();
|
||||
|
||||
if (!eventRegistration.isRegistered()) { // remove any existing registration
|
||||
event.getRegistrations().removeIf(registration -> registration.getPlayer().equals(player));
|
||||
} else {
|
||||
var optionalExistingPlayerRegistration = event.getRegistrations().stream()
|
||||
.filter(registration -> registration.getPlayer().equals(player))
|
||||
.findAny();
|
||||
if (optionalExistingPlayerRegistration.isEmpty()) { // no previous registration for this event
|
||||
var newRegistration = new Registration();
|
||||
newRegistration.setTournament(tournament);
|
||||
newRegistration.setEvent(event);
|
||||
newRegistration.setPlayer(player);
|
||||
if (eventRegistration.getPartner() != null){
|
||||
var partner = playerService.findPlayerById(eventRegistration.getPartner());
|
||||
newRegistration.setPartner(partner);
|
||||
}
|
||||
event.addRegistration(newRegistration);
|
||||
} else { // change existing registration
|
||||
var existingPlayerRegistration = optionalExistingPlayerRegistration.get();
|
||||
if (eventRegistration.getPartner() != null){
|
||||
var partner = playerService.findPlayerById(eventRegistration.getPartner());
|
||||
existingPlayerRegistration.setPartner(partner);
|
||||
} else {
|
||||
existingPlayerRegistration.setPartner(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tournamentService.saveTournament(tournament);
|
||||
}
|
||||
}
|
||||
51
src/main/java/nl/connectedit/swiss/service/ServiceUtil.java
Normal file
51
src/main/java/nl/connectedit/swiss/service/ServiceUtil.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import nl.connectedit.swiss.domain.entity.Event;
|
||||
import nl.connectedit.swiss.domain.entity.Group;
|
||||
import nl.connectedit.swiss.domain.entity.Match;
|
||||
import nl.connectedit.swiss.domain.entity.Round;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ServiceUtil {
|
||||
|
||||
static Group getGroup(Tournament tournament, Long groupId) {
|
||||
return tournament.getEvents()
|
||||
.stream()
|
||||
.map(Event::getGroups)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(group -> Objects.equals(group.getId(), groupId))
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
static Round getRound(Tournament tournament, Long roundId) {
|
||||
return tournament.getEvents()
|
||||
.stream()
|
||||
.map(Event::getGroups)
|
||||
.flatMap(Collection::stream)
|
||||
.map(Group::getRounds)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(round -> Objects.equals(round.getId(), roundId))
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
static Match getMatch(Tournament tournament, Long matchId) {
|
||||
return tournament.getEvents()
|
||||
.stream()
|
||||
.map(Event::getGroups)
|
||||
.flatMap(Collection::stream)
|
||||
.map(Group::getRounds)
|
||||
.flatMap(Collection::stream)
|
||||
.map(Round::getMatches)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(match -> Objects.equals(match.getId(), matchId))
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
}
|
||||
116
src/main/java/nl/connectedit/swiss/service/StandingsService.java
Normal file
116
src/main/java/nl/connectedit/swiss/service/StandingsService.java
Normal file
@@ -0,0 +1,116 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import nl.connectedit.swiss.domain.entity.Group;
|
||||
import nl.connectedit.swiss.domain.entity.Match;
|
||||
import nl.connectedit.swiss.domain.entity.Round;
|
||||
import nl.connectedit.swiss.domain.entity.Team;
|
||||
import nl.connectedit.swiss.dto.StandingsEntry;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class StandingsService {
|
||||
|
||||
public List<StandingsEntry> getStandings(List<Round> rounds, List<Team> teams) {
|
||||
var standings = new ArrayList<StandingsEntry>();
|
||||
teams.forEach(team -> standings.add(new StandingsEntry(team)));
|
||||
if (rounds != null) {
|
||||
for (var round : rounds) {
|
||||
addRoundToStandings(standings, round);
|
||||
}
|
||||
}
|
||||
return sortStandings(standings);
|
||||
}
|
||||
|
||||
private void addRoundToStandings(List<StandingsEntry> standings, Round round) {
|
||||
var matches = round.getMatches();
|
||||
|
||||
for (var match : matches) {
|
||||
addMatchToStandingsEntry(standings, match);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMatchToStandingsEntry(List<StandingsEntry> standings, Match match) {
|
||||
if (!match.getPlayed()) return;
|
||||
|
||||
var standingTeam1 = getStandingsEntryForTeam(standings, match.getTeam1());
|
||||
var standingTeam2 = getStandingsEntryForTeam(standings, match.getTeam2());
|
||||
|
||||
standingTeam1.setPlayed(standingTeam1.getPlayed() + 1);
|
||||
standingTeam2.setPlayed(standingTeam2.getPlayed() + 1);
|
||||
|
||||
standingTeam1.setPointsWon(standingTeam1.getPointsWon() + match.getGames().get(0).getScore1());
|
||||
standingTeam2.setPointsWon(standingTeam2.getPointsWon() + match.getGames().get(0).getScore2());
|
||||
standingTeam1.setPointsLost(standingTeam1.getPointsLost() + match.getGames().get(0).getScore2());
|
||||
standingTeam2.setPointsLost(standingTeam2.getPointsLost() + match.getGames().get(0).getScore1());
|
||||
|
||||
standingTeam1.setPointsWon(standingTeam1.getPointsWon() + match.getGames().get(1).getScore1());
|
||||
standingTeam2.setPointsWon(standingTeam2.getPointsWon() + match.getGames().get(1).getScore2());
|
||||
standingTeam1.setPointsLost(standingTeam1.getPointsLost() + match.getGames().get(1).getScore2());
|
||||
standingTeam2.setPointsLost(standingTeam2.getPointsLost() + match.getGames().get(1).getScore1());
|
||||
|
||||
if (match.getGames().size() == 3) {
|
||||
standingTeam1.setPointsWon(standingTeam1.getPointsWon() + match.getGames().get(2).getScore1());
|
||||
standingTeam2.setPointsWon(standingTeam2.getPointsWon() + match.getGames().get(2).getScore2());
|
||||
standingTeam1.setPointsLost(standingTeam1.getPointsLost() + match.getGames().get(2).getScore2());
|
||||
standingTeam2.setPointsLost(standingTeam2.getPointsLost() + match.getGames().get(2).getScore1());
|
||||
|
||||
if (match.getGames().get(2).getScore1() > match.getGames().get(2).getScore2()) {
|
||||
standingTeam1.setWon(standingTeam1.getWon() + 1);
|
||||
standingTeam1.setPoints(standingTeam1.getPoints() + 2);
|
||||
standingTeam1.setGamesWon(standingTeam1.getGamesWon() + 2);
|
||||
standingTeam1.setGamesLost(standingTeam1.getGamesLost() + 1);
|
||||
|
||||
standingTeam2.setLost(standingTeam2.getLost() + 1);
|
||||
standingTeam2.setGamesWon(standingTeam2.getGamesWon() + 1);
|
||||
standingTeam2.setGamesLost(standingTeam2.getGamesLost() + 2);
|
||||
} else {
|
||||
standingTeam1.setLost(standingTeam1.getLost() + 1);
|
||||
standingTeam1.setGamesWon(standingTeam1.getGamesWon() + 1);
|
||||
standingTeam1.setGamesLost(standingTeam1.getGamesLost() + 2);
|
||||
|
||||
standingTeam2.setWon(standingTeam2.getWon() + 1);
|
||||
standingTeam2.setPoints(standingTeam2.getPoints() + 2);
|
||||
standingTeam2.setGamesWon(standingTeam2.getGamesWon() + 2);
|
||||
standingTeam2.setGamesLost(standingTeam2.getGamesLost() + 1);
|
||||
}
|
||||
} else {
|
||||
if (match.getGames().get(1).getScore1() > match.getGames().get(1).getScore2()) {
|
||||
standingTeam1.setWon(standingTeam1.getWon() + 1);
|
||||
standingTeam1.setPoints(standingTeam1.getPoints() + 2);
|
||||
standingTeam1.setGamesWon(standingTeam1.getGamesWon() + 2);
|
||||
|
||||
standingTeam2.setLost(standingTeam2.getLost() + 1);
|
||||
standingTeam2.setGamesLost(standingTeam2.getGamesLost() + 2);
|
||||
} else {
|
||||
standingTeam1.setLost(standingTeam1.getLost() + 1);
|
||||
standingTeam1.setGamesLost(standingTeam2.getGamesLost() + 2);
|
||||
|
||||
standingTeam2.setWon(standingTeam2.getWon() + 1);
|
||||
standingTeam2.setPoints(standingTeam2.getPoints() + 2);
|
||||
standingTeam2.setGamesWon(standingTeam2.getGamesWon() + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StandingsEntry getStandingsEntryForTeam(List<StandingsEntry> standings, Team team) {
|
||||
return standings.stream().filter(standingsEntry -> Objects.equals(standingsEntry.getTeam(), team)).findAny().orElse(null);
|
||||
}
|
||||
|
||||
private List<StandingsEntry> sortStandings(List<StandingsEntry> standings) {
|
||||
var sortedStandings = standings
|
||||
.stream()
|
||||
.sorted(StandingsEntry::compare)
|
||||
.toList();
|
||||
|
||||
var position = 0L;
|
||||
for (var standing : sortedStandings) {
|
||||
standing.setPosition(++position);
|
||||
}
|
||||
return sortedStandings;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.EventType;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.domain.entity.Event;
|
||||
import nl.connectedit.swiss.domain.entity.Group;
|
||||
import nl.connectedit.swiss.domain.entity.Registration;
|
||||
import nl.connectedit.swiss.domain.entity.Team;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.repository.TournamentRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentDivideService {
|
||||
|
||||
private final TournamentValidationService tournamentValidationService;
|
||||
|
||||
private final TournamentRepository tournamentRepository;
|
||||
|
||||
@Transactional
|
||||
public Tournament divide(Tournament tournament) {
|
||||
if (tournamentValidationService.validate(tournament).hasErrors()) {
|
||||
return tournament;
|
||||
}
|
||||
|
||||
for (var event : tournament.getEvents()) {
|
||||
if (event.getRegistrations().size() >= 4) {
|
||||
divide(event);
|
||||
}
|
||||
}
|
||||
|
||||
tournament.setStatus(TournamentStatus.DIVIDED);
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
|
||||
return tournament;
|
||||
}
|
||||
|
||||
public void divide(Event event) {
|
||||
List<Registration> registrations;
|
||||
if (event.getType().isDoublesEvent()) {
|
||||
registrations = groupRegistrations(event.getRegistrations());
|
||||
} else {
|
||||
registrations = event.getRegistrations();
|
||||
}
|
||||
|
||||
event.setGroups(new ArrayList<>());
|
||||
|
||||
if (registrations.size() <= 16) {
|
||||
var group = getGroup(registrations, event.getType());
|
||||
group.setEvent(event);
|
||||
event.getGroups().add(group);
|
||||
} else {
|
||||
var groups = getGroups(registrations, event.getType());
|
||||
event.getGroups().addAll(groups);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Registration> groupRegistrations(List<Registration> registrations) {
|
||||
var groupedRegistrations = new ArrayList<Registration>();
|
||||
|
||||
nextRegistration:
|
||||
for (var registration : registrations) {
|
||||
for (var groupedRegistration : groupedRegistrations) {
|
||||
if (Objects.equals(groupedRegistration.getPartner(), registration.getPlayer())) {
|
||||
continue nextRegistration;
|
||||
}
|
||||
}
|
||||
groupedRegistrations.add(registration);
|
||||
}
|
||||
return groupedRegistrations;
|
||||
}
|
||||
|
||||
private Group getGroup(List<Registration> registrations, EventType type) {
|
||||
var group = new Group();
|
||||
group.setName(type.getText());
|
||||
group.setType(type);
|
||||
group.setStatus(Status.IN_PROGRESS);
|
||||
group.setTeams(new ArrayList<>());
|
||||
for (var registration : registrations) {
|
||||
group.getTeams().add(getTeam(registration, group));
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
private List<Group> getGroups(List<Registration> orgRegistrations, EventType type) {
|
||||
var registrations = new ArrayList<>(orgRegistrations);
|
||||
|
||||
var group1 = new Group();
|
||||
group1.setName(type.getText() + " 1");
|
||||
group1.setType(type);
|
||||
group1.setStatus(Status.IN_PROGRESS);
|
||||
group1.setTeams(new ArrayList<>());
|
||||
var group2 = new Group();
|
||||
group2.setName(type.getText() + " 2");
|
||||
group2.setType(type);
|
||||
group2.setStatus(Status.IN_PROGRESS);
|
||||
group2.setTeams(new ArrayList<>());
|
||||
|
||||
var registrationStrengthMap = new HashMap<Registration, Integer>();
|
||||
for (var registration : registrations) {
|
||||
var strength = registration.getPlayer().getStrength().getCoefficient();
|
||||
if (registration.getPartner() != null) {
|
||||
strength += registration.getPartner().getStrength().getCoefficient();
|
||||
}
|
||||
registrationStrengthMap.put(registration, strength);
|
||||
}
|
||||
|
||||
var sortedRegistrations = registrationStrengthMap
|
||||
.entrySet()
|
||||
.stream()
|
||||
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
|
||||
.map(Map.Entry::getKey)
|
||||
.toList();
|
||||
|
||||
for (Iterator<Registration> i = sortedRegistrations.iterator(); i.hasNext(); ) {
|
||||
group1.getTeams().add(getTeam(i.next(), group1));
|
||||
if (i.hasNext()) {
|
||||
group2.getTeams().add(getTeam(i.next(), group2));
|
||||
}
|
||||
}
|
||||
|
||||
return List.of(group1, group2);
|
||||
}
|
||||
|
||||
private Team getTeam(Registration registration, Group group) {
|
||||
var team = new Team();
|
||||
team.setPlayer1(registration.getPlayer());
|
||||
team.setPlayer2(registration.getPartner());
|
||||
team.setGroup(group);
|
||||
|
||||
return team;
|
||||
}
|
||||
|
||||
public Tournament clear(Tournament tournament) {
|
||||
for (var event : tournament.getEvents()) {
|
||||
event.getGroups().clear();
|
||||
}
|
||||
tournament.setStatus(TournamentStatus.UPCOMING);
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
|
||||
return tournament;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.domain.entity.*;
|
||||
import nl.connectedit.swiss.repository.TournamentRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentDrawService {
|
||||
|
||||
private final TournamentRepository tournamentRepository;
|
||||
|
||||
public Tournament draw(Tournament tournament) {
|
||||
if (!tournamentIsReadyForDraw(tournament)) return null;
|
||||
|
||||
for (var event : tournament.getEvents()) {
|
||||
for (var group : event.getGroups()) {
|
||||
var round = new Round();
|
||||
round.setName("Ronde 1");
|
||||
round.setGroup(group);
|
||||
round.setMatches(createMatchList(group, round));
|
||||
round.setStatus(Status.NOT_STARTED);
|
||||
group.getRounds().add(round);
|
||||
}
|
||||
}
|
||||
|
||||
registerTournamentPlayers(tournament);
|
||||
|
||||
tournament.setStatus(TournamentStatus.DRAWN);
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
|
||||
return tournament;
|
||||
}
|
||||
|
||||
private void registerTournamentPlayers(Tournament tournament) {
|
||||
var players = new HashSet<Player>();
|
||||
for (var event : tournament.getEvents()) {
|
||||
for (var group : event.getGroups()) {
|
||||
for (var team : group.getTeams()) {
|
||||
players.add(team.getPlayer1());
|
||||
if (team.getPlayer2() != null) players.add(team.getPlayer2());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var player : players) {
|
||||
var tournamentPlayer = new TournamentPlayer();
|
||||
tournamentPlayer.setTournament(tournament);
|
||||
tournamentPlayer.setPlayer(player);
|
||||
tournamentPlayer.setEvents(
|
||||
tournament.getEvents()
|
||||
.stream()
|
||||
.filter(event ->
|
||||
event.getRegistrations()
|
||||
.stream()
|
||||
.anyMatch(r -> r.getPlayer().equals(player)))
|
||||
.map(Event::getType)
|
||||
.map(Enum::name)
|
||||
.toList()
|
||||
);
|
||||
tournament.getTournamentPlayers().add(tournamentPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
public Tournament clear(Tournament tournament) {
|
||||
if (!tournamentIsDrawn(tournament)) return tournament;
|
||||
|
||||
for (var event : tournament.getEvents()) {
|
||||
for (var group : event.getGroups()) {
|
||||
group.getRounds().clear();
|
||||
}
|
||||
}
|
||||
|
||||
tournament.getTournamentPlayers().clear();
|
||||
|
||||
tournament.setStatus(TournamentStatus.DIVIDED);
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
|
||||
return tournament;
|
||||
}
|
||||
|
||||
private List<Match> createMatchList(Group group, Round round) {
|
||||
List<Match> matches;
|
||||
var drawCounter = 0;
|
||||
do {
|
||||
drawCounter++;
|
||||
matches = new ArrayList<>();
|
||||
var teams = new ArrayList<>(group.getTeams());
|
||||
|
||||
Collections.shuffle(teams);
|
||||
|
||||
for (Iterator<Team> i = teams.iterator(); i.hasNext(); ) {
|
||||
var match = new Match();
|
||||
match.setType(group.getType());
|
||||
match.setStatus(Status.NOT_STARTED);
|
||||
match.setTeam1(i.next());
|
||||
if (i.hasNext()) {
|
||||
match.setTeam2(i.next());
|
||||
} else {
|
||||
round.setDrawnOut(match.getTeam1());
|
||||
break;
|
||||
}
|
||||
match.setPlayed(false);
|
||||
match.setRound(round);
|
||||
matches.add(match);
|
||||
}
|
||||
} while (!drawIsValid(matches) || drawCounter == 1000);
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
private boolean drawIsValid(List<Match> matches) {
|
||||
for (var match : matches) {
|
||||
var clubs = getClubsFromMatch(match);
|
||||
var distinctClubs = new HashSet<>(clubs).size();
|
||||
if (!match.getType().isDoublesEvent()) {
|
||||
if (distinctClubs == 1) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (distinctClubs == 1) {
|
||||
return false;
|
||||
} else if (distinctClubs == 2 && (teamPlayersHaveDifferentClub(match.getTeam1()) ^ teamPlayersHaveDifferentClub(match.getTeam2()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<String> getClubsFromMatch(Match match) {
|
||||
var clubs = new ArrayList<String>();
|
||||
|
||||
clubs.add(match.getTeam1().getPlayer1().getClub());
|
||||
if (match.getTeam1().getPlayer2() != null) {
|
||||
clubs.add(match.getTeam1().getPlayer2().getClub());
|
||||
}
|
||||
clubs.add(match.getTeam2().getPlayer1().getClub());
|
||||
if (match.getTeam2().getPlayer2() != null) {
|
||||
clubs.add(match.getTeam2().getPlayer2().getClub());
|
||||
}
|
||||
|
||||
return clubs;
|
||||
}
|
||||
|
||||
private boolean teamPlayersHaveDifferentClub(Team team) {
|
||||
if (team.getPlayer2() == null) return true;
|
||||
|
||||
return !Objects.equals(team.getPlayer1().getClub(), team.getPlayer2().getClub());
|
||||
}
|
||||
|
||||
private boolean tournamentIsReadyForDraw(Tournament tournament) {
|
||||
return tournament.getStatus() == TournamentStatus.DIVIDED &&
|
||||
tournament.getEvents()
|
||||
.stream()
|
||||
.map(Event::getGroups)
|
||||
.flatMap(List::stream)
|
||||
.map(Group::getRounds)
|
||||
.flatMap(List::stream)
|
||||
.toList()
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
private boolean tournamentIsDrawn(Tournament tournament) {
|
||||
if (tournament.getStatus() != TournamentStatus.DRAWN) return false;
|
||||
|
||||
for (var event : tournament.getEvents()) {
|
||||
for (var group : event.getGroups()) {
|
||||
for (var round : group.getRounds()) {
|
||||
if (round.getStatus() != Status.NOT_STARTED) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.java.Log;
|
||||
import nl.connectedit.swiss.domain.Status;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.domain.entity.*;
|
||||
import nl.connectedit.swiss.dto.ResultDto;
|
||||
import nl.connectedit.swiss.dto.StandingsEntry;
|
||||
import nl.connectedit.swiss.repository.TournamentRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static nl.connectedit.swiss.service.ServiceUtil.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Log
|
||||
public class TournamentPlayService {
|
||||
|
||||
private final TournamentRepository tournamentRepository;
|
||||
|
||||
private final StandingsService standingsService;
|
||||
|
||||
public Tournament startRound(Tournament tournament, Long roundId) {
|
||||
getRound(tournament, roundId).setStatus(Status.IN_PROGRESS);
|
||||
tournament.setStatus(TournamentStatus.ONGOING);
|
||||
tournamentRepository.save(tournament);
|
||||
return tournament;
|
||||
}
|
||||
|
||||
public Tournament finishRound(Tournament tournament, Long roundId) {
|
||||
getRound(tournament, roundId).setStatus(Status.FINISHED);
|
||||
tournamentRepository.save(tournament);
|
||||
return tournament;
|
||||
}
|
||||
|
||||
public Tournament finishGroup(Tournament tournament, Long groupId) {
|
||||
getGroup(tournament, groupId).setStatus(Status.FINISHED);
|
||||
tournamentRepository.save(tournament);
|
||||
return tournament;
|
||||
}
|
||||
|
||||
public Tournament newRound(Tournament tournament, Long groupId) {
|
||||
var group = getGroup(tournament, groupId);
|
||||
|
||||
var standings = standingsService.getStandings(group.getRounds(), group.getTeams());
|
||||
var remainingTeams = standings.stream()
|
||||
.map(StandingsEntry::getTeam)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
var round = new Round();
|
||||
round.setName("Ronde " + (group.getRounds().size() + 1));
|
||||
round.setGroup(group);
|
||||
round.setStatus(Status.NOT_STARTED);
|
||||
|
||||
if (remainingTeams.size() % 2 == 1) {
|
||||
var random = new Random();
|
||||
var drawnOutPlayers = getDrawnOutPlayers(tournament);
|
||||
do {
|
||||
var randomTeam = remainingTeams.get(random.nextInt(remainingTeams.size()));
|
||||
if (!drawnOutPlayers.contains(randomTeam.getPlayer1()) && (randomTeam.getPlayer2() == null || !drawnOutPlayers.contains(randomTeam.getPlayer2()))) {
|
||||
remainingTeams.remove(randomTeam);
|
||||
round.setDrawnOut(randomTeam);
|
||||
break;
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
|
||||
var matches = tryMatches(remainingTeams, group).reversed();
|
||||
|
||||
for (var match : matches) {
|
||||
match.setType(group.getType());
|
||||
match.setStatus(Status.NOT_STARTED);
|
||||
match.setPlayed(false);
|
||||
match.setRound(round);
|
||||
}
|
||||
|
||||
round.setMatches(matches);
|
||||
|
||||
printRound(round, standings);
|
||||
|
||||
group.getRounds().add(round);
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
return tournament;
|
||||
}
|
||||
|
||||
private List<Player> getDrawnOutPlayers(Tournament tournament) {
|
||||
var players = new ArrayList<Player>();
|
||||
|
||||
for (var event : tournament.getEvents()) {
|
||||
for (var group : event.getGroups()) {
|
||||
var playersInGroup = group.getTeams().stream()
|
||||
.map(this::getPlayersInTeam)
|
||||
.flatMap(List::stream)
|
||||
.toList();
|
||||
|
||||
for (var player : playersInGroup) {
|
||||
for (var round : group.getRounds()) {
|
||||
var foundInRound = false;
|
||||
for (var match : round.getMatches()) {
|
||||
if (playerIsInMatch(match, player)) {
|
||||
foundInRound = true;
|
||||
}
|
||||
}
|
||||
if (!foundInRound) {
|
||||
players.add(player);
|
||||
log.info(player.getFullName() + " is al uitgeloot in het toernooi.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
private List<Player> getPlayersInTeam(Team team) {
|
||||
return team.getPlayer2() == null ? List.of(team.getPlayer1()) : List.of(team.getPlayer1(), team.getPlayer2());
|
||||
}
|
||||
|
||||
private boolean playerIsInTeam(Team team, Player player) {
|
||||
return Objects.equals(team.getPlayer1(), player) || Objects.equals(team.getPlayer2(), player);
|
||||
}
|
||||
|
||||
private boolean playerIsInMatch(Match match, Player player) {
|
||||
return playerIsInTeam(match.getTeam1(), player) || playerIsInTeam(match.getTeam2(), player);
|
||||
}
|
||||
|
||||
private void printRound(Round round, List<StandingsEntry> standings) {
|
||||
for (var match: round.getMatches()) {
|
||||
log.info("%s - %s".formatted(
|
||||
String.valueOf(standings.stream().filter(entry -> entry.getTeam().equals(match.getTeam1())).map(StandingsEntry::getPosition).findFirst().get()),
|
||||
String.valueOf(standings.stream().filter(entry -> entry.getTeam().equals(match.getTeam2())).map(StandingsEntry::getPosition).findFirst().get())));
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConflictInDrawException extends RuntimeException {}
|
||||
|
||||
private List<Match> tryMatches(List<Team> remainingTeams, Group group) {
|
||||
var newMatches = new ArrayList<Match>();
|
||||
if (remainingTeams.isEmpty()) {
|
||||
return newMatches;
|
||||
}
|
||||
var newMatch = new Match();
|
||||
newMatch.setTeam1(remainingTeams.getFirst());
|
||||
for (var opponentIndex = 1; opponentIndex < remainingTeams.size(); opponentIndex++) {
|
||||
if (!findPreviousMatchOccurence(newMatch.getTeam1(), remainingTeams.get(opponentIndex), group)) {
|
||||
newMatch.setTeam2(remainingTeams.get(opponentIndex));
|
||||
} else {
|
||||
log.info("Wedstrijd %s - %s kwam al eerder voor.".formatted(newMatch.getTeam1().toString(), remainingTeams.get(opponentIndex).toString()));
|
||||
continue;
|
||||
}
|
||||
var newRemainingTeams = getRemainingTeams(remainingTeams, opponentIndex);
|
||||
if (newRemainingTeams.size() == 1) {
|
||||
newMatches.add(newMatch);
|
||||
break;
|
||||
} else {
|
||||
try {
|
||||
newMatches.addAll(tryMatches(newRemainingTeams, group));
|
||||
newMatches.add(newMatch);
|
||||
break;
|
||||
} catch (ConflictInDrawException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newMatch.getTeam2() == null) {
|
||||
log.info("Geen tegenstander gevonden voor %s.".formatted(newMatch.getTeam1().toString()));
|
||||
throw new ConflictInDrawException();
|
||||
}
|
||||
|
||||
return newMatches;
|
||||
}
|
||||
|
||||
private List<Team> getRemainingTeams(List<Team> remainingTeams, int opponentIndex) {
|
||||
var newRemainingTeams = new ArrayList<Team>();
|
||||
for (var remainingTeamIndex = 1; remainingTeamIndex < remainingTeams.size(); remainingTeamIndex++) {
|
||||
if (remainingTeamIndex == opponentIndex) continue;
|
||||
newRemainingTeams.add(remainingTeams.get(remainingTeamIndex));
|
||||
}
|
||||
return newRemainingTeams;
|
||||
}
|
||||
|
||||
private boolean findPreviousMatchOccurence(Team team1, Team team2, Group group) {
|
||||
for (var round : group.getRounds()) {
|
||||
for (var match : round.getMatches()) {
|
||||
if ((Objects.equals(match.getTeam1(), team1) && Objects.equals(match.getTeam2(), team2))
|
||||
|| (Objects.equals(match.getTeam1(), team2) && Objects.equals(match.getTeam2(), team1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean playerHasSkippedRoundBefore(Player player, Tournament tournament) {
|
||||
var hasSkippedRound = false;
|
||||
|
||||
return hasSkippedRound;
|
||||
}
|
||||
|
||||
public Tournament startMatch(Tournament tournament, Long matchId, Long court) {
|
||||
var match = getMatch(tournament, matchId);
|
||||
match.setStatus(Status.IN_PROGRESS);
|
||||
match.setStartTime(LocalDateTime.now());
|
||||
match.setCourt(court);
|
||||
tournamentRepository.save(tournament);
|
||||
return tournament;
|
||||
}
|
||||
|
||||
public Tournament stopMatch(Tournament tournament, Long matchId) {
|
||||
var match = getMatch(tournament, matchId);
|
||||
match.setStatus(Status.NOT_STARTED);
|
||||
match.setStartTime(null);
|
||||
match.setCourt(null);
|
||||
tournamentRepository.save(tournament);
|
||||
return tournament;
|
||||
}
|
||||
|
||||
public Tournament saveResult(Tournament tournament, Long matchId, ResultDto result) {
|
||||
var match = getMatch(tournament, matchId);
|
||||
if (match.getGames().isEmpty()) {
|
||||
match.setEndTime(LocalDateTime.now());
|
||||
match.setStatus(Status.FINISHED);
|
||||
match.setPlayed(true);
|
||||
}
|
||||
match.getGames().clear();
|
||||
match.getGames().addAll(resultToGames(result, match));
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
return tournament;
|
||||
}
|
||||
|
||||
private List<Game> resultToGames(ResultDto result, Match match) {
|
||||
var games = new ArrayList<Game>();
|
||||
for (var game : result.getGames()) {
|
||||
if (game.getScore1() != null) {
|
||||
games.add(Game.builder()
|
||||
.score1(game.getScore1())
|
||||
.score2(game.getScore2())
|
||||
.match(match)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
return games;
|
||||
}
|
||||
|
||||
public void updatePaid(Tournament tournament, Long playerId, Boolean paid) {
|
||||
var tournamentPlayer = tournament.getTournamentPlayers()
|
||||
.stream()
|
||||
.filter(player -> player.getPlayer().getId().equals(playerId))
|
||||
.findFirst()
|
||||
.get();
|
||||
|
||||
tournamentPlayer.setPaid(paid);
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
}
|
||||
|
||||
public void updatePresent(Tournament tournament, Long playerId, Boolean present) {
|
||||
var tournamentPlayer = tournament.getTournamentPlayers()
|
||||
.stream()
|
||||
.filter(player -> player.getPlayer().getId().equals(playerId))
|
||||
.findFirst()
|
||||
.get();
|
||||
|
||||
tournamentPlayer.setPresent(present);
|
||||
|
||||
tournamentRepository.save(tournament);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.repository.TournamentRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentService {
|
||||
|
||||
private final TournamentRepository tournamentRepository;
|
||||
|
||||
public List<Tournament> findAllTournaments() {
|
||||
return tournamentRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Tournament> findAllTournamentsWithStatus(TournamentStatus status) {
|
||||
return tournamentRepository.findAllByStatus(status);
|
||||
}
|
||||
|
||||
public Tournament findTournamentById(Long id) {
|
||||
return tournamentRepository.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
public Tournament saveTournament(Tournament tournament) {
|
||||
return tournamentRepository.save(tournament);
|
||||
}
|
||||
|
||||
public Tournament updateTournament(Long tournamentId, Tournament newTournament) {
|
||||
Tournament tournament = findTournamentById(tournamentId);
|
||||
tournament.setName(newTournament.getName());
|
||||
tournament.setDate(newTournament.getDate());
|
||||
tournament.setMaxEvents(newTournament.getMaxEvents());
|
||||
tournament.setCostsPerEvent(newTournament.getCostsPerEvent());
|
||||
tournament.setCourts(newTournament.getCourts());
|
||||
return tournamentRepository.save(tournament);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package nl.connectedit.swiss.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.domain.*;
|
||||
import nl.connectedit.swiss.domain.entity.Event;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.domain.entity.Registration;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static nl.connectedit.swiss.domain.Validation.Severity.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentValidationService {
|
||||
|
||||
private final PlayerService playerService;
|
||||
|
||||
public TournamentValidation validate(Tournament tournament) {
|
||||
var players = playerService.findAllPlayers();
|
||||
|
||||
TournamentValidation tournamentValidation = new TournamentValidation();
|
||||
tournamentValidation.setTournamentId(tournament.getId());
|
||||
|
||||
var validations = new ArrayList<Validation>();
|
||||
checkForTooManyRegistrationsPerPlayer(tournament, players, validations);
|
||||
|
||||
tournamentValidation.setValidations(validations);
|
||||
|
||||
tournamentValidation.setEventValidations(tournament
|
||||
.getEvents()
|
||||
.stream()
|
||||
.map(this::validate)
|
||||
.toList()
|
||||
);
|
||||
|
||||
return tournamentValidation;
|
||||
}
|
||||
|
||||
private EventValidation validate(Event event) {
|
||||
var validations = new ArrayList<Validation>();
|
||||
|
||||
if (event.getStatus() != Status.NOT_STARTED) {
|
||||
return EventValidation.builder().eventId(event.getId()).build();
|
||||
}
|
||||
|
||||
checkNumberOfRegistrations(event, validations);
|
||||
checkMultipleGroupsNeeded(event, validations);
|
||||
|
||||
if (event.getType().isDoublesEvent()) {
|
||||
checkForEmptyPartnerRegistrations(event, validations);
|
||||
checkForInvalidPartnerRegistrations(event, validations);
|
||||
checkForMultiplePartnerRegistrations(event, validations);
|
||||
}
|
||||
|
||||
return EventValidation.builder().eventId(event.getId()).validations(validations).build();
|
||||
|
||||
}
|
||||
|
||||
private void checkNumberOfRegistrations(Event event, List<Validation> validations) {
|
||||
if (event.getRegistrations().isEmpty()) {
|
||||
addValidation(validations, ERROR, "Geen inschrijvingen");
|
||||
} else if (event.getRegistrations().size() < 4 ) {
|
||||
addValidation(validations, ERROR, "Te weinig inschrijvingen");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMultipleGroupsNeeded(Event event, List<Validation> validations) {
|
||||
if (event.getType().isDoublesEvent()) {
|
||||
if (event.getRegistrations().size() > 32) {
|
||||
addValidation(validations, WARN, "Meer dan 32 inschrijvingen, 2 groepen nodig");
|
||||
}
|
||||
} else {
|
||||
if (event.getRegistrations().size() > 16) {
|
||||
addValidation(validations, WARN, "Meer dan 16 inschrijvingen, 2 groepen nodig");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForEmptyPartnerRegistrations(Event event, List<Validation> validations) {
|
||||
var registrations = event.getRegistrations();
|
||||
|
||||
for (var registration : registrations) {
|
||||
var partner = registration.getPartner();
|
||||
if (partner == null) {
|
||||
addValidation(validations, ERROR, "%s heeft geen partner", registration.getPlayer().getFullName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForInvalidPartnerRegistrations(Event event, List<Validation> validations) {
|
||||
var registrations = event.getRegistrations();
|
||||
|
||||
for (var registration : registrations) {
|
||||
if (registration.getPartner() != null) {
|
||||
var optionalPartnerRegistration = getRegistrationForPlayer(registrations, registration.getPartner());
|
||||
if (optionalPartnerRegistration.isEmpty()) {
|
||||
addValidation(validations, ERROR,
|
||||
"%s heeft als geregistreerde partner %s, maar deze staat niet ingeschreven voor het onderdeel %s",
|
||||
registration.getPlayer().getFullName(), registration.getPartner().getFullName(), event.getType().getText());
|
||||
} else {
|
||||
var partnerRegistration = optionalPartnerRegistration.get();
|
||||
var partnerPartner = partnerRegistration.getPartner();
|
||||
if (partnerPartner == null) {
|
||||
addValidation(validations, ERROR,
|
||||
"%s heeft als geregistreerde partner %s, maar deze heeft nog geen geregistreerde partner",
|
||||
registration.getPlayer().getFullName(), partnerRegistration.getPlayer().getFullName());
|
||||
} else {
|
||||
if (!Objects.equals(registration.getPlayer(), partnerPartner)) {
|
||||
addValidation(validations, ERROR,
|
||||
"%s heeft als geregistreerde partner %s, maar deze staat ingeschreven met partner %s",
|
||||
registration.getPlayer().getFullName(), partnerRegistration.getPlayer().getFullName(), partnerRegistration.getPartner().getFullName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForMultiplePartnerRegistrations(Event event, List<Validation> validations) {
|
||||
var registrations = event.getRegistrations();
|
||||
|
||||
for (var registration : registrations) {
|
||||
var partners = getPartners(registrations, registration.getPlayer());
|
||||
if (partners.size() > 1) {
|
||||
addValidation(validations, ERROR,
|
||||
"%s is met meerdere spelers als partner geregistreerd (%s)",
|
||||
registration.getPlayer().getFullName(), getPlayersAsList(partners));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForTooManyRegistrationsPerPlayer(Tournament tournament, List<Player> players, List<Validation> validations) {
|
||||
var playerRegistrations = new ArrayList<Registration>();
|
||||
for (var player : players) {
|
||||
playerRegistrations.clear();
|
||||
for (var event : tournament.getEvents()) {
|
||||
var eventRegistration = getRegistrationForPlayer(event.getRegistrations(), player);
|
||||
eventRegistration.ifPresent(playerRegistrations::add);
|
||||
}
|
||||
if (playerRegistrations.size() > tournament.getMaxEvents()) {
|
||||
addValidation(validations, ERROR,
|
||||
"%s staat voor meer dan %d onderdelen ingeschreven, nl. %s",
|
||||
player.getFullName(), tournament.getMaxEvents(), getEventsAsList(playerRegistrations, tournament));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getEventsAsList(List<Registration> registrations, Tournament tournament) {
|
||||
if (registrations.isEmpty()) {
|
||||
return "";
|
||||
} else if (registrations.size() == 1) {
|
||||
return tournament
|
||||
.getEvents()
|
||||
.stream()
|
||||
.filter(event -> event.getRegistrations().contains(registrations.getFirst()))
|
||||
.findFirst()
|
||||
.get()
|
||||
.getType()
|
||||
.getText();
|
||||
} else {
|
||||
return String.join(", ", registrations
|
||||
.stream()
|
||||
.limit(registrations.size() - 1)
|
||||
.map(registration -> this.getTypeForRegistration(registration, tournament))
|
||||
.map(EventType::getText)
|
||||
.toList()
|
||||
) + " en " + getTypeForRegistration(registrations.getLast(), tournament).getText();
|
||||
}
|
||||
}
|
||||
|
||||
private EventType getTypeForRegistration(Registration registration, Tournament tournament) {
|
||||
return tournament
|
||||
.getEvents()
|
||||
.stream()
|
||||
.filter(event -> event.getRegistrations().contains(registration))
|
||||
.findFirst()
|
||||
.get()
|
||||
.getType();
|
||||
}
|
||||
|
||||
private String getPlayersAsList(List<Player> players) {
|
||||
if (players.isEmpty()) {
|
||||
return "";
|
||||
} else if (players.size() == 1) {
|
||||
return players.getFirst().getFullName();
|
||||
} else {
|
||||
return String.join(", ", players
|
||||
.stream()
|
||||
.limit(players.size() - 1)
|
||||
.map(Player::getFullName)
|
||||
.toList()
|
||||
) + " en " + players.getLast().getFullName();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Registration> getRegistrationForPlayer(List<Registration> registrations, Player player) {
|
||||
return registrations
|
||||
.stream()
|
||||
.filter(registration -> Objects.equals(registration.getPlayer(), player)).findFirst();
|
||||
}
|
||||
|
||||
|
||||
private List<Player> getPartners(List<Registration> registrations, Player player) {
|
||||
List<Player> partners = new ArrayList<>();
|
||||
for (var registration : registrations) {
|
||||
if (registration.getPartner() != null && registration.getPartner().equals(player)) {
|
||||
partners.add(registration.getPlayer());
|
||||
}
|
||||
}
|
||||
return partners;
|
||||
}
|
||||
|
||||
private void addValidation(List<Validation> validations, Validation.Severity severity, String message, Object... params) {
|
||||
validations.add(new Validation(severity, message.formatted(params)));
|
||||
}
|
||||
|
||||
}
|
||||
27
src/main/resources/application-local-postgres.yaml
Executable file
27
src/main/resources/application-local-postgres.yaml
Executable file
@@ -0,0 +1,27 @@
|
||||
spring:
|
||||
application:
|
||||
name: swiss
|
||||
# autoconfigure:
|
||||
# exclude:
|
||||
# - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||
# - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
|
||||
datasource:
|
||||
url: jdbc:postgresql://localhost:5432/swiss?currentSchema=swiss
|
||||
username: ${DB_USERNAME:postgres}
|
||||
password: ${DB_PASSWORD:postgres}
|
||||
flyway:
|
||||
enabled: false
|
||||
|
||||
security: true
|
||||
#logging:
|
||||
# level:
|
||||
# root: DEBUG
|
||||
#logging:
|
||||
# level:
|
||||
# org:
|
||||
# hibernate:
|
||||
# sql: DEBUG
|
||||
# type:
|
||||
# descriptor:
|
||||
# sql:
|
||||
# BasicBinder: TRACE
|
||||
39
src/main/resources/application-local.yaml
Executable file
39
src/main/resources/application-local.yaml
Executable file
@@ -0,0 +1,39 @@
|
||||
spring:
|
||||
application:
|
||||
name: swiss
|
||||
# autoconfigure:
|
||||
# exclude:
|
||||
# - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||
# - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
|
||||
datasource:
|
||||
url: jdbc:h2:file:./localswiss
|
||||
driver-class-name: org.h2.Driver
|
||||
username: sa
|
||||
password: password
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.H2Dialect
|
||||
hibernate:
|
||||
ddl-auto: create-drop
|
||||
jackson:
|
||||
serialization:
|
||||
indent-output: true
|
||||
flyway:
|
||||
url: jdbc:h2:file:./localswiss
|
||||
user: sa
|
||||
password: password
|
||||
locations: flyway
|
||||
baseline-on-migrate: true
|
||||
|
||||
security: true
|
||||
#logging:
|
||||
# level:
|
||||
# root: DEBUG
|
||||
#logging:
|
||||
# level:
|
||||
# org:
|
||||
# hibernate:
|
||||
# sql: DEBUG
|
||||
# type:
|
||||
# descriptor:
|
||||
# sql:
|
||||
# BasicBinder: TRACE
|
||||
33
src/main/resources/application.yaml
Executable file
33
src/main/resources/application.yaml
Executable file
@@ -0,0 +1,33 @@
|
||||
spring:
|
||||
application:
|
||||
name: swiss
|
||||
# autoconfigure:
|
||||
# exclude:
|
||||
# - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||
# - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
|
||||
datasource:
|
||||
url: jdbc:postgresql://${DB_URL:localhost:5432}/swiss?currentSchema=swiss
|
||||
username: ${DB_USERNAME:postgres}
|
||||
password: ${DB_PASSWORD:postgres}
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
flyway:
|
||||
url: jdbc:postgresql://${DB_URL:localhost:5432}/swiss?currentSchema=swiss
|
||||
user: ${DB_USERNAME:postgres}
|
||||
password: ${DB_PASSWORD:postgres}
|
||||
baseline-on-migrate: true
|
||||
|
||||
management:
|
||||
server:
|
||||
port: 8081
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: "*"
|
||||
endpoint:
|
||||
health:
|
||||
probes:
|
||||
enabled: true
|
||||
|
||||
security: true
|
||||
28
src/main/resources/certs/private.pem
Normal file
28
src/main/resources/certs/private.pem
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCp5PMrGbzVKQSE
|
||||
LSSkMoJnPUKu0f+ySIRe39qd5r1w07S6TAEqIwBdXwCdwTo8QnggNNxlC3j2pa0J
|
||||
lKI3cNrnNitcs8oI0jQ4LN/HsN/cwp3V+m0sBaEVt9mZK0qSj2mxx+EnHpLF3Z+L
|
||||
7EAGPlezpyGKsJHi1hgAXcbKdLcfC/h3g/TtIvPj7VfR86VGArY2VsZQWFsKvkQa
|
||||
rGVosARQo0b2L/qsqYr9CvCEZ6gSTMS0+xr9Fc9AsYOyuzsw2zHvq8i/L8alK/Tt
|
||||
CJobZK1O0Kedbv5R1gEU+NhGzrdZe1YwCCg5QZCk6j9NXN8tpMIFpeORsxXWxB72
|
||||
Dzc6+/FNAgMBAAECggEAB/mFeYkyfi339o1Y6jUtvlNXkTWtwyxYvExVKnLFgymI
|
||||
0vLU3im472kRchY7Gc+D7H0WuE5+zdMOiYPWznPnbpFyHR6aVeoqBdYDZg/1Hhtr
|
||||
hbsEy1tzSX3xApnP3QvKygvIE4pBmPSTc+Gxyqk7/CSU9DngCy4B/+hm96NdYiFd
|
||||
yI5VByp+DMhk/dtgWFOHZcG4MvrRaLA8ZRnSkCa5QrL+la3lf4M9FJedpo9GvjG6
|
||||
c8M+pgLKMmw4bFDqfDyEpYhJxQaAqEMFaiBuMMDymI6OXpzBG92kflK7VvR4YBym
|
||||
DUhqhmQ4qAe37Wr2vVob+Dsf39IuS+FWDNZSW6lrMQKBgQDnGVBv0Xv3+pb/NmqA
|
||||
1sRJvhMtFaVkIKJuf1qK7SNzU5tCbNAfaJgQQVFNswnjpbS300T1ehNorsDeDi05
|
||||
WqeWdRPY/Qz+19AJ1UiCMUku/SWWN21byUQU4yven6mJ6rgkKbAv4E4VtpcG3q8B
|
||||
W/aIL1KAHvEFJ3rI21QD4A+NvQKBgQC8M1rlXu64kKbw4D5KormMFvjkoROsXwn/
|
||||
eqN0wCN9avD7+LN/MUhqn7S0t0iQJRH+kaOjS6yl1v9JFI8bBLMQ1Uk1Mtpi4Mvl
|
||||
AWtPLUYXxeP+zlS1ueBuDzRsNUGRqYM1MVlr7sko5gOAPQHHaDbNRYSqaskLtRR0
|
||||
/BjItmDC0QKBgGCySOPgxXxnUBMNk9bBBnTMoX111zRkK1MM2rfSrcitrQNIQHVD
|
||||
8Iysp/ZY+cRVK57XOb11DPX6WR0Q1X9wHTtpVZqvl2ZyqsvSgHppYPPWXInUO1/y
|
||||
gRg0TcDjEa9xlQccomoF8uZG9j6boqJw9mDZXC3bxIGhmVC95ROSBzAJAoGBAJHz
|
||||
3dUuV0IpZF4/+e8V3YHIOwPL657tIarQ6Dzd2WglbHhsun+0r62I57KSxaKMLTVY
|
||||
qygzwtPmNZruZ8ETVu+CCUFJi9XM8jNKc3c27Dn5jUSJrWY1ndic0BHvB0e4x3mU
|
||||
KP4sdDLUlvh3145WwtFUzXsAT6RVrWTAMVRPJCFRAoGBAMEW8V36c+XJuD9qDvg3
|
||||
qG3uPaGS1IytkpSAtfSV+hXJ14N57L/oxPTVyrZKDgu0ic3KAHEJG/WN+SQPfaWT
|
||||
zj8YnFFeSISRRo4Y1Q4Rg/Yer5fKVdkvGKPR9lCEhbxEBqZz4qSMUHGak1exjTeW
|
||||
DapsPxEG0wEN8rMoNzYMNuc3
|
||||
-----END PRIVATE KEY-----
|
||||
9
src/main/resources/certs/public.pem
Normal file
9
src/main/resources/certs/public.pem
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqeTzKxm81SkEhC0kpDKC
|
||||
Zz1CrtH/skiEXt/anea9cNO0ukwBKiMAXV8AncE6PEJ4IDTcZQt49qWtCZSiN3Da
|
||||
5zYrXLPKCNI0OCzfx7Df3MKd1fptLAWhFbfZmStKko9pscfhJx6Sxd2fi+xABj5X
|
||||
s6chirCR4tYYAF3GynS3Hwv4d4P07SLz4+1X0fOlRgK2NlbGUFhbCr5EGqxlaLAE
|
||||
UKNG9i/6rKmK/QrwhGeoEkzEtPsa/RXPQLGDsrs7MNsx76vIvy/GpSv07QiaG2St
|
||||
TtCnnW7+UdYBFPjYRs63WXtWMAgoOUGQpOo/TVzfLaTCBaXjkbMV1sQe9g83Ovvx
|
||||
TQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
303
src/main/resources/db/migration/V1__init.sql
Normal file
303
src/main/resources/db/migration/V1__init.sql
Normal file
@@ -0,0 +1,303 @@
|
||||
create table player
|
||||
(
|
||||
birthday date not null,
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
club varchar(255),
|
||||
email varchar(255) not null,
|
||||
first_name varchar(255) not null,
|
||||
last_name varchar(255) not null,
|
||||
middle_name varchar(255),
|
||||
phone_number varchar(255) not null,
|
||||
sex varchar(255) not null
|
||||
constraint player_sex_check
|
||||
check ((sex)::text = ANY ((ARRAY ['M'::character varying, 'V'::character varying])::text[])),
|
||||
strength varchar(255) not null
|
||||
constraint player_strength_check
|
||||
check ((strength)::text = ANY
|
||||
((ARRAY ['D5'::character varying, 'D6'::character varying, 'D7'::character varying, 'D8'::character varying, 'D9'::character varying, 'DR'::character varying])::text[]))
|
||||
);
|
||||
|
||||
create table tournament
|
||||
(
|
||||
date date,
|
||||
courts bigint,
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
max_events bigint,
|
||||
name varchar(255),
|
||||
status varchar(255)
|
||||
constraint tournament_status_check
|
||||
check ((status)::text = ANY
|
||||
((ARRAY ['UPCOMING'::character varying, 'DIVIDED'::character varying, 'DRAWN'::character varying, 'ONGOING'::character varying, 'CLOSED'::character varying])::text[]))
|
||||
);
|
||||
|
||||
create table event
|
||||
(
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
tournament_id bigint
|
||||
constraint fkidhc25ppai44aclt55uu9n0fd
|
||||
references tournament on delete cascade,
|
||||
status varchar(255)
|
||||
constraint event_status_check
|
||||
check ((status)::text = ANY
|
||||
((ARRAY ['NOT_STARTED'::character varying, 'READY_TO_PLAY'::character varying, 'IN_PROGRESS'::character varying, 'FINISHED'::character varying])::text[])),
|
||||
type varchar(255)
|
||||
constraint event_type_check
|
||||
check ((type)::text = ANY
|
||||
((ARRAY ['HE'::character varying, 'DE'::character varying, 'HD'::character varying, 'DD'::character varying, 'GD'::character varying])::text[]))
|
||||
);
|
||||
|
||||
create table eventgroup
|
||||
(
|
||||
type smallint
|
||||
constraint eventgroup_type_check
|
||||
check ((type >= 0) AND (type <= 4)),
|
||||
event_id bigint
|
||||
constraint fksdpnxwfbha8j4fiwcxkfyknhv
|
||||
references event on delete cascade,
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
name varchar(255),
|
||||
status varchar(255)
|
||||
constraint eventgroup_status_check
|
||||
check ((status)::text = ANY
|
||||
((ARRAY ['NOT_STARTED'::character varying, 'READY_TO_PLAY'::character varying, 'IN_PROGRESS'::character varying, 'FINISHED'::character varying])::text[]))
|
||||
);
|
||||
|
||||
create table event_groups
|
||||
(
|
||||
event_id bigint not null
|
||||
constraint fkd4r6j627kmoyxt2k0814d8k18
|
||||
references event on delete cascade,
|
||||
groups_id bigint not null
|
||||
unique
|
||||
constraint fkg4tgtn29hlh54nqxvk3uplupr
|
||||
references eventgroup on delete cascade
|
||||
);
|
||||
|
||||
create table registration
|
||||
(
|
||||
event_id bigint
|
||||
constraint fks4x1uat6i8fx26qpdrfwfg3ya
|
||||
references event on delete cascade,
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
partner_id bigint
|
||||
constraint fkhmyyu2ljiwo8x10kjfab1pkru
|
||||
references player on delete cascade,
|
||||
player_id bigint
|
||||
constraint fkswk5vywwvd2r4knle35xjygao
|
||||
references player on delete cascade,
|
||||
tournament_id bigint
|
||||
constraint fktfm09huujek0o03wklcg9ewpq
|
||||
references tournament on delete cascade
|
||||
);
|
||||
|
||||
create table event_registrations
|
||||
(
|
||||
event_id bigint not null
|
||||
constraint fks4kjleulewhu881p4nygwdi0
|
||||
references event on delete cascade,
|
||||
registrations_id bigint not null
|
||||
unique
|
||||
constraint fkl4jouqv1u8b3wvwv97i1cqmm7
|
||||
references registration on delete cascade
|
||||
);
|
||||
|
||||
create table player_partner_registrations
|
||||
(
|
||||
partner_registrations_id bigint not null
|
||||
unique
|
||||
constraint fkohcyc057xfh1bq2gcjjhx90b5
|
||||
references registration on delete cascade,
|
||||
player_id bigint not null
|
||||
constraint fk61ldsgn3vwru4tjdiraxrsaeb
|
||||
references player on delete cascade
|
||||
);
|
||||
|
||||
create table player_registrations
|
||||
(
|
||||
player_id bigint not null
|
||||
constraint fklc29ku8hopaa9wbmru6dtbax3
|
||||
references player on delete cascade,
|
||||
registrations_id bigint not null
|
||||
unique
|
||||
constraint fkasxo61ngph7cyje01l1n1ldhg
|
||||
references registration on delete cascade
|
||||
);
|
||||
|
||||
create table team
|
||||
(
|
||||
group_id bigint
|
||||
constraint fk6sh9ago3tae2l8og75kbrf4mx
|
||||
references eventgroup on delete cascade,
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
player1_id bigint
|
||||
constraint fkphn10d6c8k5b758iklivfyn5y
|
||||
references player on delete cascade,
|
||||
player2_id bigint
|
||||
constraint fk962rmngjyud0ijcw4w7d9vfs0
|
||||
references player on delete cascade
|
||||
);
|
||||
|
||||
create table eventgroup_teams
|
||||
(
|
||||
group_id bigint not null
|
||||
constraint fk2o8i34jh5bk79ya6pc8w3k9of
|
||||
references eventgroup on delete cascade,
|
||||
teams_id bigint not null
|
||||
unique
|
||||
constraint fk832tg34v55x5kuma6ia55w4dq
|
||||
references team on delete cascade
|
||||
);
|
||||
|
||||
create table round
|
||||
(
|
||||
status smallint
|
||||
constraint round_status_check
|
||||
check ((status >= 0) AND (status <= 3)),
|
||||
drawn_out_id bigint
|
||||
constraint fk3w19bu9yiv9px837huabw6abs
|
||||
references team on delete cascade,
|
||||
group_id bigint
|
||||
constraint fk3ytfpp2rat10y2x43g7cl61p3
|
||||
references eventgroup on delete cascade,
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
name varchar(255)
|
||||
);
|
||||
|
||||
create table eventgroup_rounds
|
||||
(
|
||||
group_id bigint not null
|
||||
constraint fksghgh2lq09c28y7xcsmvwd63s
|
||||
references eventgroup on delete cascade,
|
||||
rounds_id bigint not null
|
||||
unique
|
||||
constraint fkkl6r766uq2l1wpe2yals44nyw
|
||||
references round on delete cascade
|
||||
);
|
||||
|
||||
create table match
|
||||
(
|
||||
played boolean,
|
||||
status smallint
|
||||
constraint match_status_check
|
||||
check ((status >= 0) AND (status <= 3)),
|
||||
type smallint
|
||||
constraint match_type_check
|
||||
check ((type >= 0) AND (type <= 4)),
|
||||
court bigint,
|
||||
end_time timestamp(6),
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
round_id bigint
|
||||
constraint fkol8rkyfucvsv37sd7kebpm1nw
|
||||
references round on delete cascade,
|
||||
start_time timestamp(6),
|
||||
team1_id bigint
|
||||
constraint fkglt3t5urqflayn544lpn5ua3s
|
||||
references team on delete cascade,
|
||||
team2_id bigint
|
||||
constraint fkci4coem3xydhawrap0y36qlmg
|
||||
references team on delete cascade
|
||||
);
|
||||
|
||||
create table game
|
||||
(
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
match_id bigint
|
||||
constraint fkkspobx32vu8ykuguwl3u0nuhd
|
||||
references match on delete cascade,
|
||||
score1 bigint,
|
||||
score2 bigint
|
||||
);
|
||||
|
||||
create table match_games
|
||||
(
|
||||
games_id bigint not null
|
||||
unique
|
||||
constraint fkqt1fsmogbyfoo0w5bilc6rmku
|
||||
references game on delete cascade,
|
||||
match_id bigint not null
|
||||
constraint fkgab11a4ifq5ygm14rpsrvrsuh
|
||||
references match on delete cascade
|
||||
);
|
||||
|
||||
create table round_matches
|
||||
(
|
||||
matches_id bigint not null
|
||||
unique
|
||||
constraint fk9quwtp4ipel9hm56p4oh0f4fh
|
||||
references match on delete cascade,
|
||||
round_id bigint not null
|
||||
constraint fkr8lyri4t4xil8ajv8e3gjrd47
|
||||
references round on delete cascade
|
||||
);
|
||||
|
||||
create table round_quit
|
||||
(
|
||||
quit_id bigint not null
|
||||
unique
|
||||
constraint fkgjta0bnl9jey9c64pmcbbnj5v
|
||||
references team on delete cascade,
|
||||
round_id bigint not null
|
||||
constraint fknkc29tpads6tq669y77d0dvwh
|
||||
references round on delete cascade
|
||||
);
|
||||
|
||||
create table tournament_costs_per_event
|
||||
(
|
||||
costs_per_event real,
|
||||
tournament_id bigint not null
|
||||
constraint fkts9nbg8r28e9ncafhnhdohai
|
||||
references tournament on delete cascade
|
||||
);
|
||||
|
||||
create table tournament_events
|
||||
(
|
||||
events_id bigint not null
|
||||
unique
|
||||
constraint fkfo9dvc9isnkm8hj8il8ajiea6
|
||||
references event on delete cascade,
|
||||
tournament_id bigint not null
|
||||
constraint fkb4la5xkmiin27q1du88n7gbxs
|
||||
references tournament on delete cascade
|
||||
);
|
||||
|
||||
create table tournament_player
|
||||
(
|
||||
paid boolean not null,
|
||||
present boolean not null,
|
||||
id bigint generated by default as identity
|
||||
primary key,
|
||||
player_id bigint
|
||||
constraint fkrqw4qfs65btri9sfkbof5xyxq
|
||||
references player on delete cascade,
|
||||
tournament_id bigint
|
||||
constraint fkrrm3jbmm1fxx5t9t5f8t46ebc
|
||||
references tournament on delete cascade
|
||||
);
|
||||
|
||||
create table tournament_tournament_players
|
||||
(
|
||||
tournament_id bigint not null
|
||||
constraint fkn7jcr3q0c3lh5gm93t0piyjyt
|
||||
references tournament on delete cascade,
|
||||
tournament_players_id bigint not null
|
||||
unique
|
||||
constraint fkhhmn6g3oxtqiu99ch61h1ubcf
|
||||
references tournament_player on delete cascade
|
||||
);
|
||||
|
||||
create table tournament_player_events
|
||||
(
|
||||
tournament_player_id bigint not null
|
||||
constraint fksihteat3lqwdp92fkp33oglqt
|
||||
references tournament_player on delete cascade,
|
||||
events varchar(255)
|
||||
);
|
||||
3903
src/main/resources/export.sql
Executable file
3903
src/main/resources/export.sql
Executable file
File diff suppressed because it is too large
Load Diff
3855
src/main/resources/export2.sql
Executable file
3855
src/main/resources/export2.sql
Executable file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user